[sgen] Reenable gc-altstack test
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / NewArrayExpression.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
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.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 using System;
17 using System.Collections.Generic;
18 using System.Collections.ObjectModel;
19 using System.Diagnostics;
20 using System.Dynamic.Utils;
21 using System.Runtime.CompilerServices;
22
23 #if !FEATURE_CORE_DLR
24 namespace Microsoft.Scripting.Ast {
25 #else
26 namespace System.Linq.Expressions {
27 #endif
28
29     /// <summary>
30     /// Represents creating a new array and possibly initializing the elements of the new array.
31     /// </summary>
32     [DebuggerTypeProxy(typeof(Expression.NewArrayExpressionProxy))]
33     public class NewArrayExpression : Expression {
34         private readonly ReadOnlyCollection<Expression> _expressions;
35         private readonly Type _type;
36
37         internal NewArrayExpression(Type type, ReadOnlyCollection<Expression> expressions) {
38             _expressions = expressions;
39             _type = type;
40         }
41
42         internal static NewArrayExpression Make(ExpressionType nodeType, Type type, ReadOnlyCollection<Expression> expressions) {
43             if (nodeType == ExpressionType.NewArrayInit) {
44                 return new NewArrayInitExpression(type, expressions);
45             } else {
46                 return new NewArrayBoundsExpression(type, expressions);
47             }
48         }
49
50         /// <summary>
51         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
52         /// </summary>
53         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
54         public sealed override Type Type {
55             get { return _type; }
56         }
57
58         /// <summary>
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. 
60         /// </summary>
61         public ReadOnlyCollection<Expression> Expressions {
62             get { return _expressions; }
63         }
64
65         /// <summary>
66         /// Dispatches to the specific visit method for this node type.
67         /// </summary>
68         protected internal override Expression Accept(ExpressionVisitor visitor) {
69             return visitor.VisitNewArray(this);
70         }
71
72         /// <summary>
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.
76         /// </summary>
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) {
81                 return this;
82             }
83             if (NodeType == ExpressionType.NewArrayInit) {
84                 return Expression.NewArrayInit(Type.GetElementType(), expressions);
85             }
86             return Expression.NewArrayBounds(Type.GetElementType(), expressions);
87         }
88     }
89
90     internal sealed class NewArrayInitExpression : NewArrayExpression {
91         internal NewArrayInitExpression(Type type, ReadOnlyCollection<Expression> expressions)
92             : base(type, expressions) {
93         }
94
95
96         /// <summary>
97         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
98         /// </summary>
99         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
100         public sealed override ExpressionType NodeType {
101             get { return ExpressionType.NewArrayInit; }
102         }
103     }
104
105     internal sealed class NewArrayBoundsExpression : NewArrayExpression {
106         internal NewArrayBoundsExpression(Type type, ReadOnlyCollection<Expression> expressions)
107             : base(type, expressions) {
108         }
109
110         /// <summary>
111         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
112         /// </summary>
113         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
114         public sealed override ExpressionType NodeType {
115             get { return ExpressionType.NewArrayBounds; }
116         }
117     }
118     
119     public partial class Expression {
120
121         #region NewArrayInit
122
123
124         /// <summary>
125         /// Creates a new array expression of the specified type from the provided initializers.
126         /// </summary>
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);
132         }
133
134         /// <summary>
135         /// Creates a new array expression of the specified type from the provided initializers.
136         /// </summary>
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();
145             }
146
147             ReadOnlyCollection<Expression> initializerList = initializers.ToReadOnly();
148
149             Expression[] newList = null;
150             for (int i = 0, n = initializerList.Count; i < n; i++) {
151                 Expression expr = initializerList[i];
152                 RequiresCanRead(expr, "initializers");
153
154                 if (!TypeUtils.AreReferenceAssignable(type, expr.Type)) {
155                     if (!TryQuote(type, ref expr)){
156                         throw Error.ExpressionTypeCannotInitializeArrayType(expr.Type, type);
157                     }
158                     if (newList == null) {
159                         newList = new Expression[initializerList.Count];
160                         for (int j = 0; j < i; j++) {
161                             newList[j] = initializerList[j];
162                         }
163                     }
164                 }
165                 if (newList != null) {
166                     newList[i] = expr;
167                 }
168             }
169             if (newList != null) {
170                 initializerList = new TrueReadOnlyCollection<Expression>(newList);
171             }
172
173             return NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList);
174         }
175
176         #endregion
177
178         #region NewArrayBounds
179
180
181         /// <summary>
182         /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank. 
183         /// </summary>
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);
189         }
190
191
192         /// <summary>
193         /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank. 
194         /// </summary>
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");
201
202             if (type.Equals(typeof(void))) {
203                 throw Error.ArgumentCannotBeOfTypeVoid();
204             }
205
206             ReadOnlyCollection<Expression> boundsList = bounds.ToReadOnly();
207
208             int dimensions = boundsList.Count;
209             if (dimensions <= 0) throw Error.BoundsCannotBeLessThanOne();
210
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();
216                 }
217             }
218
219             Type arrayType;
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();
224             } else {
225                 arrayType = type.MakeArrayType(dimensions);
226             }
227
228             return NewArrayExpression.Make(ExpressionType.NewArrayBounds, arrayType, bounds.ToReadOnly());
229         }
230
231         #endregion
232
233     }
234 }