Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / InvocationExpression.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.Reflection;
22
23 #if !FEATURE_CORE_DLR
24 namespace Microsoft.Scripting.Ast {
25 #else
26 namespace System.Linq.Expressions {
27 #endif
28     /// <summary>
29     /// Represents an expression that applies a delegate or lambda expression to a list of argument expressions.
30     /// </summary>
31     [DebuggerTypeProxy(typeof(Expression.InvocationExpressionProxy))]
32     public sealed class InvocationExpression : Expression, IArgumentProvider {
33         private IList<Expression> _arguments;
34         private readonly Expression _lambda;
35         private readonly Type _returnType;
36
37         internal InvocationExpression(Expression lambda, IList<Expression> arguments, Type returnType) {
38             _lambda = lambda;
39             _arguments = arguments;
40             _returnType = returnType;
41         }
42
43         /// <summary>
44         /// Gets the static type of the expression that this <see cref="Expression" /> represents.
45         /// </summary>
46         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
47         public sealed override Type Type {
48             get { return _returnType; }
49         }
50
51         /// <summary>
52         /// Returns the node type of this Expression. Extension nodes should return
53         /// ExpressionType.Extension when overriding this method.
54         /// </summary>
55         /// <returns>The <see cref="ExpressionType"/> of the expression.</returns>
56         public sealed override ExpressionType NodeType {
57             get { return ExpressionType.Invoke; }
58         }
59
60         /// <summary>
61         /// Gets the delegate or lambda expression to be applied.
62         /// </summary>
63         public Expression Expression {
64             get { return _lambda; }
65         }
66
67         /// <summary>
68         /// Gets the arguments that the delegate or lambda expression is applied to.
69         /// </summary>
70         public ReadOnlyCollection<Expression> Arguments {
71             get { return ReturnReadOnly(ref _arguments); }
72         }
73
74         /// <summary>
75         /// Creates a new expression that is like this one, but using the
76         /// supplied children. If all of the children are the same, it will
77         /// return this expression.
78         /// </summary>
79         /// <param name="expression">The <see cref="Expression" /> property of the result.</param>
80         /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
81         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
82         public InvocationExpression Update(Expression expression, IEnumerable<Expression> arguments) {
83             if (expression == Expression && arguments == Arguments) {
84                 return this;
85             }
86
87             return Expression.Invoke(expression, arguments);
88         }
89
90         Expression IArgumentProvider.GetArgument(int index) {
91             return _arguments[index];
92         }
93
94         int IArgumentProvider.ArgumentCount {
95             get {
96                 return _arguments.Count;
97             }
98         }
99
100         /// <summary>
101         /// Dispatches to the specific visit method for this node type.
102         /// </summary>
103         protected internal override Expression Accept(ExpressionVisitor visitor) {
104             return visitor.VisitInvocation(this);
105         }
106
107         internal InvocationExpression Rewrite(Expression lambda, Expression[] arguments) {
108             Debug.Assert(lambda != null);
109             Debug.Assert(arguments == null || arguments.Length == _arguments.Count);
110
111             return Expression.Invoke(lambda, arguments ?? _arguments);
112         }
113
114         internal LambdaExpression LambdaOperand {
115             get {
116                 return (_lambda.NodeType == ExpressionType.Quote)
117                     ? (LambdaExpression)((UnaryExpression)_lambda).Operand
118                     : (_lambda as LambdaExpression);
119             }
120         }
121     }
122
123     public partial class Expression {
124
125         ///<summary>
126         ///Creates an <see cref="T:System.Linq.Expressions.InvocationExpression" /> that 
127         ///applies a delegate or lambda expression to a list of argument expressions.
128         ///</summary>
129         ///<returns>
130         ///An <see cref="T:System.Linq.Expressions.InvocationExpression" /> that 
131         ///applies the specified delegate or lambda expression to the provided arguments.
132         ///</returns>
133         ///<param name="expression">
134         ///An <see cref="T:System.Linq.Expressions.Expression" /> that represents the delegate
135         ///or lambda expression to be applied.
136         ///</param>
137         ///<param name="arguments">
138         ///An array of <see cref="T:System.Linq.Expressions.Expression" /> objects
139         ///that represent the arguments that the delegate or lambda expression is applied to.
140         ///</param>
141         ///<exception cref="T:System.ArgumentNullException">
142         ///<paramref name="expression" /> is null.</exception>
143         ///<exception cref="T:System.ArgumentException">
144         ///<paramref name="expression" />.Type does not represent a delegate type or an <see cref="T:System.Linq.Expressions.Expression`1" />.-or-The <see cref="P:System.Linq.Expressions.Expression.Type" /> property of an element of <paramref name="arguments" /> is not assignable to the type of the corresponding parameter of the delegate represented by <paramref name="expression" />.</exception>
145         ///<exception cref="T:System.InvalidOperationException">
146         ///<paramref name="arguments" /> does not contain the same number of elements as the list of parameters for the delegate represented by <paramref name="expression" />.</exception>
147         public static InvocationExpression Invoke(Expression expression, params Expression[] arguments) {
148             return Invoke(expression, (IEnumerable<Expression>)arguments);
149         }
150
151         ///<summary>
152         ///Creates an <see cref="T:System.Linq.Expressions.InvocationExpression" /> that 
153         ///applies a delegate or lambda expression to a list of argument expressions.
154         ///</summary>
155         ///<returns>
156         ///An <see cref="T:System.Linq.Expressions.InvocationExpression" /> that 
157         ///applies the specified delegate or lambda expression to the provided arguments.
158         ///</returns>
159         ///<param name="expression">
160         ///An <see cref="T:System.Linq.Expressions.Expression" /> that represents the delegate
161         ///or lambda expression to be applied.
162         ///</param>
163         ///<param name="arguments">
164         ///An <see cref="T:System.Collections.Generic.IEnumerable`1" /> of <see cref="T:System.Linq.Expressions.Expression" /> objects
165         ///that represent the arguments that the delegate or lambda expression is applied to.
166         ///</param>
167         ///<exception cref="T:System.ArgumentNullException">
168         ///<paramref name="expression" /> is null.</exception>
169         ///<exception cref="T:System.ArgumentException">
170         ///<paramref name="expression" />.Type does not represent a delegate type or an <see cref="T:System.Linq.Expressions.Expression`1" />.-or-The <see cref="P:System.Linq.Expressions.Expression.Type" /> property of an element of <paramref name="arguments" /> is not assignable to the type of the corresponding parameter of the delegate represented by <paramref name="expression" />.</exception>
171         ///<exception cref="T:System.InvalidOperationException">
172         ///<paramref name="arguments" /> does not contain the same number of elements as the list of parameters for the delegate represented by <paramref name="expression" />.</exception>
173         public static InvocationExpression Invoke(Expression expression, IEnumerable<Expression> arguments) {
174             RequiresCanRead(expression, "expression");
175
176             var args = arguments.ToReadOnly();
177             var mi = GetInvokeMethod(expression);
178             ValidateArgumentTypes(mi, ExpressionType.Invoke, ref args);
179             return new InvocationExpression(expression, args, mi.ReturnType);
180         }
181
182         /// <summary>
183         /// Gets the delegate's Invoke method; used by InvocationExpression.
184         /// </summary>
185         /// <param name="expression">The expression to be invoked.</param>
186         internal static MethodInfo GetInvokeMethod(Expression expression) {
187             Type delegateType = expression.Type;
188             if (!expression.Type.IsSubclassOf(typeof(MulticastDelegate))) {
189                 Type exprType = TypeUtils.FindGenericType(typeof(Expression<>), expression.Type);
190                 if (exprType == null) {
191                     throw Error.ExpressionTypeNotInvocable(expression.Type);
192                 }
193                 delegateType = exprType.GetGenericArguments()[0];
194             }
195
196             return delegateType.GetMethod("Invoke");
197         }
198     }
199 }