Add unit test for AggregateException.GetBaseException that works on .net but is broke...
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / LambdaExpression.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 using System.Reflection.Emit;
23 using System.Threading;
24 using System.Runtime.CompilerServices;
25
26 #if !FEATURE_CORE_DLR
27 namespace Microsoft.Scripting.Ast {
28 #else
29 namespace System.Linq.Expressions {
30 #endif
31     using Compiler;
32
33     /// <summary>
34     /// Creates a <see cref="LambdaExpression"/> node.
35     /// This captures a block of code that is similar to a .NET method body.
36     /// </summary>
37     /// <remarks>
38     /// Lambda expressions take input through parameters and are expected to be fully bound. 
39     /// </remarks>
40     [DebuggerTypeProxy(typeof(Expression.LambdaExpressionProxy))]
41     public abstract class LambdaExpression : Expression {
42         private readonly string _name;
43         private readonly Expression _body;
44         private readonly ReadOnlyCollection<ParameterExpression> _parameters;
45         private readonly Type _delegateType;
46         private readonly bool _tailCall;
47
48         internal LambdaExpression(
49             Type delegateType,
50             string name,
51             Expression body,
52             bool tailCall,
53             ReadOnlyCollection<ParameterExpression> parameters
54         ) {
55
56             Debug.Assert(delegateType != null);
57
58             _name = name;
59             _body = body;
60             _parameters = parameters;
61             _delegateType = delegateType;
62             _tailCall = tailCall;
63         }
64
65         internal abstract LambdaExpression Accept(StackSpiller spiller);
66
67         /// <summary>
68         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
69         /// </summary>
70         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
71         public sealed override Type Type {
72             get { return _delegateType; }
73         }
74
75         /// <summary>
76         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
77         /// </summary>
78         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
79         public sealed override ExpressionType NodeType {
80             get { return ExpressionType.Lambda; }
81         }
82
83         /// <summary>
84         /// Gets the parameters of the lambda expression. 
85         /// </summary>
86         public ReadOnlyCollection<ParameterExpression> Parameters {
87             get { return _parameters; }
88         }
89
90         /// <summary>
91         /// Gets the name of the lambda expression. 
92         /// </summary>
93         /// <remarks>Used for debugging purposes.</remarks>
94         public string Name {
95             get { return _name; }
96         }
97
98         /// <summary>
99         /// Gets the body of the lambda expression. 
100         /// </summary>
101         public Expression Body {
102             get { return _body; }
103         }
104
105         /// <summary>
106         /// Gets the return type of the lambda expression. 
107         /// </summary>
108         public Type ReturnType {
109             get { return Type.GetMethod("Invoke").ReturnType; }
110         }
111
112         /// <summary>
113         /// Gets the value that indicates if the lambda expression will be compiled with
114         /// tail call optimization. 
115         /// </summary>
116         public bool TailCall {
117             get { return _tailCall; }
118         }
119
120         /// <summary>
121         /// Produces a delegate that represents the lambda expression.
122         /// </summary>
123         /// <returns>A delegate containing the compiled version of the lambda.</returns>
124         public Delegate Compile() {
125             return LambdaCompiler.Compile(this, null);
126         }
127
128         /// <summary>
129         /// Produces a delegate that represents the lambda expression.
130         /// </summary>
131         /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
132         /// <returns>A delegate containing the compiled version of the lambda.</returns>
133         public Delegate Compile(DebugInfoGenerator debugInfoGenerator) {
134             ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
135             return LambdaCompiler.Compile(this, debugInfoGenerator);
136         }
137
138 #if FEATURE_REFEMIT
139         /// <summary>
140         /// Compiles the lambda into a method definition.
141         /// </summary>
142         /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
143         public void CompileToMethod(MethodBuilder method) {
144             CompileToMethodInternal(method, null);
145         }
146
147         /// <summary>
148         /// Compiles the lambda into a method definition and custom debug information.
149         /// </summary>
150         /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param>
151         /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
152         public void CompileToMethod(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
153             ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
154             CompileToMethodInternal(method, debugInfoGenerator);
155         }
156
157         private void CompileToMethodInternal(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) {
158             ContractUtils.RequiresNotNull(method, "method");
159             ContractUtils.Requires(method.IsStatic, "method");
160             var type = method.DeclaringType as TypeBuilder;
161             if (type == null) throw Error.MethodBuilderDoesNotHaveTypeBuilder();
162
163             LambdaCompiler.Compile(this, method, debugInfoGenerator);
164         }
165 #endif
166     }
167
168     /// <summary>
169     /// Defines a <see cref="Expression{TDelegate}"/> node.
170     /// This captures a block of code that is similar to a .NET method body.
171     /// </summary>
172     /// <typeparam name="TDelegate">The type of the delegate.</typeparam>
173     /// <remarks>
174     /// Lambda expressions take input through parameters and are expected to be fully bound. 
175     /// </remarks>
176     public sealed class Expression<TDelegate> : LambdaExpression {
177         internal Expression(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters)
178             : base(typeof(TDelegate), name, body, tailCall, parameters) {
179         }
180
181         /// <summary>
182         /// Produces a delegate that represents the lambda expression.
183         /// </summary>
184         /// <returns>A delegate containing the compiled version of the lambda.</returns>
185         public new TDelegate Compile() {
186             return (TDelegate)(object)LambdaCompiler.Compile(this, null);
187         }
188
189         /// <summary>
190         /// Produces a delegate that represents the lambda expression.
191         /// </summary>
192         /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param>
193         /// <returns>A delegate containing the compiled version of the lambda.</returns>
194         public new TDelegate Compile(DebugInfoGenerator debugInfoGenerator) {
195             ContractUtils.RequiresNotNull(debugInfoGenerator, "debugInfoGenerator");
196             return (TDelegate)(object)LambdaCompiler.Compile(this, debugInfoGenerator);
197         }
198
199         /// <summary>
200         /// Creates a new expression that is like this one, but using the
201         /// supplied children. If all of the children are the same, it will
202         /// return this expression.
203         /// </summary>
204         /// <param name="body">The <see cref="LambdaExpression.Body">Body</see> property of the result.</param>
205         /// <param name="parameters">The <see cref="LambdaExpression.Parameters">Parameters</see> property of the result.</param>
206         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
207         public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters) {
208             if (body == Body && parameters == Parameters) {
209                 return this;
210             }
211             return Expression.Lambda<TDelegate>(body, Name, TailCall, parameters);
212         }
213
214         /// <summary>
215         /// Dispatches to the specific visit method for this node type.
216         /// </summary>
217         protected internal override Expression Accept(ExpressionVisitor visitor) {
218             return visitor.VisitLambda(this);
219         }
220
221         internal override LambdaExpression Accept(StackSpiller spiller) {
222             return spiller.Rewrite(this);
223         }
224
225         internal static LambdaExpression Create(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
226             return new Expression<TDelegate>(body, name, tailCall, parameters);
227         }
228     }
229
230
231     public partial class Expression {
232
233         /// <summary>
234         /// Creates an Expression{T} given the delegate type. Caches the
235         /// factory method to speed up repeated creations for the same T.
236         /// </summary>
237         internal static LambdaExpression CreateLambda(Type delegateType, Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters) {
238             // Get or create a delegate to the public Expression.Lambda<T>
239             // method and call that will be used for creating instances of this
240             // delegate type
241             LambdaFactory fastPath;
242             if (_LambdaFactories == null) {
243                 // NOTE: this must be Interlocked assigment since we use _LambdaFactories for locking.
244                 Interlocked.CompareExchange(ref _LambdaFactories, new CacheDict<Type, LambdaFactory>(50), null);
245             }
246
247             MethodInfo create = null;
248             lock (_LambdaFactories) {
249                 if (!_LambdaFactories.TryGetValue(delegateType, out fastPath)) {
250                     create = typeof(Expression<>).MakeGenericType(delegateType).GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic);
251                     if (TypeUtils.CanCache(delegateType)) {
252                         _LambdaFactories[delegateType] = fastPath = (LambdaFactory)Delegate.CreateDelegate(typeof(LambdaFactory), create);
253                     }
254                 }
255             }
256
257             if (fastPath != null) {
258                 return fastPath(body, name, tailCall, parameters);
259             }
260             
261             Debug.Assert(create != null);
262             return (LambdaExpression)create.Invoke(null, new object[] { body, name, tailCall, parameters });
263         }
264
265         /// <summary>
266         /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time. 
267         /// </summary>
268         /// <typeparam name="TDelegate">The delegate type. </typeparam>
269         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
270         /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
271         /// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
272         public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters) {
273             return Lambda<TDelegate>(body, false, (IEnumerable<ParameterExpression>)parameters);
274         }
275
276         /// <summary>
277         /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time. 
278         /// </summary>
279         /// <typeparam name="TDelegate">The delegate type. </typeparam>
280         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
281         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
282         /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
283         /// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
284         public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, params ParameterExpression[] parameters) {
285             return Lambda<TDelegate>(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
286         }
287
288         /// <summary>
289         /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time. 
290         /// </summary>
291         /// <typeparam name="TDelegate">The delegate type. </typeparam>
292         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
293         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
294         /// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
295         public static Expression<TDelegate> Lambda<TDelegate>(Expression body, IEnumerable<ParameterExpression> parameters) {
296             return Lambda<TDelegate>(body, null, false, parameters);
297         }
298
299         /// <summary>
300         /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time. 
301         /// </summary>
302         /// <typeparam name="TDelegate">The delegate type. </typeparam>
303         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
304         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
305         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
306         /// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
307         public static Expression<TDelegate> Lambda<TDelegate>(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
308             return Lambda<TDelegate>(body, null, tailCall, parameters);
309         }
310
311         /// <summary>
312         /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time. 
313         /// </summary>
314         /// <typeparam name="TDelegate">The delegate type. </typeparam>
315         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
316         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
317         /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
318         /// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
319         public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, IEnumerable<ParameterExpression> parameters) {
320             return Lambda<TDelegate>(body, name, false, parameters);
321         }
322
323         /// <summary>
324         /// Creates an <see cref="Expression{TDelegate}"/> where the delegate type is known at compile time. 
325         /// </summary>
326         /// <typeparam name="TDelegate">The delegate type. </typeparam>
327         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
328         /// <param name="name">The name of the lambda. Used for generating debugging info.</param>
329         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
330         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
331         /// <returns>An <see cref="Expression{TDelegate}"/> that has the <see cref="P:NodeType"/> property equal to <see cref="P:Lambda"/> and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
332         public static Expression<TDelegate> Lambda<TDelegate>(Expression body, String name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
333             var parameterList = parameters.ToReadOnly();
334             ValidateLambdaArgs(typeof(TDelegate), ref body, parameterList);
335             return new Expression<TDelegate>(body, name, tailCall, parameterList);
336         }
337
338
339         /// <summary>
340         /// Creates a LambdaExpression by first constructing a delegate type. 
341         /// </summary>
342         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
343         /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
344         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
345         public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters) {
346             return Lambda(body, false, (IEnumerable<ParameterExpression>)parameters);
347         }
348
349         /// <summary>
350         /// Creates a LambdaExpression by first constructing a delegate type. 
351         /// </summary>
352         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
353         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
354         /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
355         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
356         public static LambdaExpression Lambda(Expression body, bool tailCall, params ParameterExpression[] parameters) {
357             return Lambda(body, tailCall, (IEnumerable<ParameterExpression>)parameters);
358         }
359
360         /// <summary>
361         /// Creates a LambdaExpression by first constructing a delegate type. 
362         /// </summary>
363         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
364         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
365         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
366         public static LambdaExpression Lambda(Expression body, IEnumerable<ParameterExpression> parameters) {
367             return Lambda(body, null, false, parameters);
368         }
369
370         /// <summary>
371         /// Creates a LambdaExpression by first constructing a delegate type. 
372         /// </summary>
373         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
374         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
375         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
376         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
377         public static LambdaExpression Lambda(Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
378             return Lambda(body, null, tailCall, parameters);
379         }
380
381         /// <summary>
382         /// Creates a LambdaExpression by first constructing a delegate type. 
383         /// </summary>
384         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
385         /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
386         /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
387         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
388         public static LambdaExpression Lambda(Type delegateType, Expression body, params ParameterExpression[] parameters) {
389             return Lambda(delegateType, body, null, false, parameters);
390         }
391
392         /// <summary>
393         /// Creates a LambdaExpression by first constructing a delegate type. 
394         /// </summary>
395         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
396         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
397         /// <param name="parameters">An array that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
398         /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
399         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
400         public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, params ParameterExpression[] parameters) {
401             return Lambda(delegateType, body, null, tailCall, parameters);
402         }
403
404         /// <summary>
405         /// Creates a LambdaExpression by first constructing a delegate type. 
406         /// </summary>
407         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
408         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
409         /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
410         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
411         public static LambdaExpression Lambda(Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters) {
412             return Lambda(delegateType, body, null, false, parameters);
413         }
414
415         /// <summary>
416         /// Creates a LambdaExpression by first constructing a delegate type. 
417         /// </summary>
418         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
419         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
420         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
421         /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
422         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
423         public static LambdaExpression Lambda(Type delegateType, Expression body, bool tailCall, IEnumerable<ParameterExpression> parameters) {
424             return Lambda(delegateType, body, null, tailCall, parameters);
425         }
426
427         /// <summary>
428         /// Creates a LambdaExpression by first constructing a delegate type. 
429         /// </summary>
430         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
431         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
432         /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
433         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
434         public static LambdaExpression Lambda(Expression body, string name, IEnumerable<ParameterExpression> parameters) {
435             return Lambda(body, name, false, parameters);
436         }
437
438         /// <summary>
439         /// Creates a LambdaExpression by first constructing a delegate type. 
440         /// </summary>
441         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
442         /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
443         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
444         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
445         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
446         public static LambdaExpression Lambda(Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
447             ContractUtils.RequiresNotNull(body, "body");
448
449             var parameterList = parameters.ToReadOnly();
450
451             int paramCount = parameterList.Count;
452             Type[] typeArgs = new Type[paramCount + 1];
453             if (paramCount > 0) {
454                 var set = new Set<ParameterExpression>(parameterList.Count);
455                 for (int i = 0; i < paramCount; i++) {
456                     var param = parameterList[i];
457                     ContractUtils.RequiresNotNull(param, "parameter");
458                     typeArgs[i] = param.IsByRef ? param.Type.MakeByRefType() : param.Type;
459                     if (set.Contains(param)) {
460                         throw Error.DuplicateVariable(param);
461                     }
462                     set.Add(param);
463                 }
464             }
465             typeArgs[paramCount] = body.Type;
466
467             Type delegateType = DelegateHelpers.MakeDelegateType(typeArgs);
468
469             return CreateLambda(delegateType, body, name, tailCall, parameterList);
470         }
471
472         /// <summary>
473         /// Creates a LambdaExpression by first constructing a delegate type. 
474         /// </summary>
475         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
476         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
477         /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
478         /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
479         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
480         public static LambdaExpression Lambda(Type delegateType, Expression body, string name, IEnumerable<ParameterExpression> parameters) {
481             var paramList = parameters.ToReadOnly();
482             ValidateLambdaArgs(delegateType, ref body, paramList);
483
484             return CreateLambda(delegateType, body, name, false, paramList);
485         }
486
487         /// <summary>
488         /// Creates a LambdaExpression by first constructing a delegate type. 
489         /// </summary>
490         /// <param name="delegateType">A <see cref="Type"/> representing the delegate signature for the lambda.</param>
491         /// <param name="body">An <see cref="Expression"/> to set the <see cref="P:Body"/> property equal to. </param>
492         /// <param name="name">The name for the lambda. Used for emitting debug information.</param>
493         /// <param name="tailCall">A <see cref="Boolean"/> that indicates if tail call optimization will be applied when compiling the created expression. </param>
494         /// <param name="parameters">An <see cref="IEnumerable{T}"/> that contains <see cref="ParameterExpression"/> objects to use to populate the <see cref="P:Parameters"/> collection. </param>
495         /// <returns>A <see cref="LambdaExpression"/> that has the <see cref="P:NodeType"/> property equal to Lambda and the <see cref="P:Body"/> and <see cref="P:Parameters"/> properties set to the specified values.</returns>
496         public static LambdaExpression Lambda(Type delegateType, Expression body, string name, bool tailCall, IEnumerable<ParameterExpression> parameters) {
497             var paramList = parameters.ToReadOnly();
498             ValidateLambdaArgs(delegateType, ref body, paramList);
499
500             return CreateLambda(delegateType, body, name, tailCall, paramList);
501         }
502
503         private static void ValidateLambdaArgs(Type delegateType, ref Expression body, ReadOnlyCollection<ParameterExpression> parameters) {
504             ContractUtils.RequiresNotNull(delegateType, "delegateType");
505             RequiresCanRead(body, "body");
506
507             if (!typeof(MulticastDelegate).IsAssignableFrom(delegateType) || delegateType == typeof(MulticastDelegate)) {
508                 throw Error.LambdaTypeMustBeDerivedFromSystemDelegate();
509             }
510
511             MethodInfo mi;
512             lock (_LambdaDelegateCache) {
513                 if (!_LambdaDelegateCache.TryGetValue(delegateType, out mi)) {
514                     mi = delegateType.GetMethod("Invoke");
515                     if (TypeUtils.CanCache(delegateType)) {
516                         _LambdaDelegateCache[delegateType] = mi;
517                     }
518                 }
519             }
520
521             ParameterInfo[] pis = mi.GetParametersCached();
522
523             if (pis.Length > 0) {
524                 if (pis.Length != parameters.Count) {
525                     throw Error.IncorrectNumberOfLambdaDeclarationParameters();
526                 }
527                 var set = new Set<ParameterExpression>(pis.Length);
528                 for (int i = 0, n = pis.Length; i < n; i++) {
529                     ParameterExpression pex = parameters[i];
530                     ParameterInfo pi = pis[i];
531                     RequiresCanRead(pex, "parameters");
532                     Type pType = pi.ParameterType;
533                     if (pex.IsByRef) {
534                         if (!pType.IsByRef) {
535                             //We cannot pass a parameter of T& to a delegate that takes T or any non-ByRef type.
536                             throw Error.ParameterExpressionNotValidAsDelegate(pex.Type.MakeByRefType(), pType);
537                         }
538                         pType = pType.GetElementType();
539                     }
540                     if (!TypeUtils.AreReferenceAssignable(pex.Type, pType)) {
541                         throw Error.ParameterExpressionNotValidAsDelegate(pex.Type, pType);
542                     }
543                     if (set.Contains(pex)) {
544                         throw Error.DuplicateVariable(pex);
545                     }
546                     set.Add(pex);
547                 }
548             } else if (parameters.Count > 0) {
549                 throw Error.IncorrectNumberOfLambdaDeclarationParameters();
550             }
551             if (mi.ReturnType != typeof(void) && !TypeUtils.AreReferenceAssignable(mi.ReturnType, body.Type)) {
552                 if (!TryQuote(mi.ReturnType, ref body)) {
553                     throw Error.ExpressionTypeDoesNotMatchReturn(body.Type, mi.ReturnType);
554                 }
555             }
556         }
557
558         private static bool ValidateTryGetFuncActionArgs(Type[] typeArgs) {
559             if (typeArgs == null) {
560                 throw new ArgumentNullException("typeArgs");
561             }
562             for (int i = 0, n = typeArgs.Length; i < n; i++) {
563                 var a = typeArgs[i];
564                 if (a == null) {
565                     throw new ArgumentNullException("typeArgs");
566                 }
567                 if (a.IsByRef) {
568                     return false;
569                 }
570             }
571             return true;
572         }
573
574         /// <summary>
575         /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
576         /// The last type argument specifies the return type of the created delegate.
577         /// </summary>
578         /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
579         /// <returns>The type of a System.Func delegate that has the specified type arguments.</returns>
580         public static Type GetFuncType(params Type[] typeArgs) {
581             if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
582
583             Type result = DelegateHelpers.GetFuncType(typeArgs);
584             if (result == null) {
585                 throw Error.IncorrectNumberOfTypeArgsForFunc();
586             }
587             return result;
588         }
589
590         /// <summary>
591         /// Creates a <see cref="Type"/> object that represents a generic System.Func delegate type that has specific type arguments.
592         /// The last type argument specifies the return type of the created delegate.
593         /// </summary>
594         /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Func delegate type.</param>
595         /// <param name="funcType">When this method returns, contains the generic System.Func delegate type that has specific type arguments. Contains null if there is no generic System.Func delegate that matches the <paramref name="typeArgs"/>.This parameter is passed uninitialized.</param>
596         /// <returns>true if generic System.Func delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
597         public static bool TryGetFuncType(Type[] typeArgs, out Type funcType) {
598             if (ValidateTryGetFuncActionArgs(typeArgs)) {
599                 return (funcType = DelegateHelpers.GetFuncType(typeArgs)) != null;
600             }
601             funcType = null;
602             return false;
603         }
604
605         /// <summary>
606         /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments. 
607         /// </summary>
608         /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
609         /// <returns>The type of a System.Action delegate that has the specified type arguments.</returns>
610         public static Type GetActionType(params Type[] typeArgs) {
611             if (!ValidateTryGetFuncActionArgs(typeArgs)) throw Error.TypeMustNotBeByRef();
612
613             Type result = DelegateHelpers.GetActionType(typeArgs);
614             if (result == null) {
615                 throw Error.IncorrectNumberOfTypeArgsForAction();
616             }
617             return result;
618         }
619
620         /// <summary>
621         /// Creates a <see cref="Type"/> object that represents a generic System.Action delegate type that has specific type arguments.
622         /// </summary>
623         /// <param name="typeArgs">An array of Type objects that specify the type arguments for the System.Action delegate type.</param>
624         /// <param name="actionType">When this method returns, contains the generic System.Action delegate type that has specific type arguments. Contains null if there is no generic System.Action delegate that matches the <paramref name="typeArgs"/>.This parameter is passed uninitialized.</param>
625         /// <returns>true if generic System.Action delegate type was created for specific <paramref name="typeArgs"/>; false otherwise.</returns>
626         public static bool TryGetActionType(Type[] typeArgs, out Type actionType) {
627             if (ValidateTryGetFuncActionArgs(typeArgs)) {
628                 return (actionType = DelegateHelpers.GetActionType(typeArgs)) != null;
629             }
630             actionType = null;
631             return false;
632         }
633
634         /// <summary>
635         /// Gets a <see cref="Type"/> object that represents a generic System.Func or System.Action delegate type that has specific type arguments.
636         /// The last type argument determines the return type of the delegate. If no Func or Action is large enough, it will generate a custom
637         /// delegate type.
638         /// </summary>
639         /// <param name="typeArgs">The type arguments of the delegate.</param>
640         /// <returns>The delegate type.</returns>
641         /// <remarks>
642         /// As with Func, the last argument is the return type. It can be set
643         /// to System.Void to produce an Action.</remarks>
644         public static Type GetDelegateType(params Type[] typeArgs) {
645             ContractUtils.RequiresNotEmpty(typeArgs, "typeArgs");
646             ContractUtils.RequiresNotNullItems(typeArgs, "typeArgs");
647             return DelegateHelpers.MakeDelegateType(typeArgs);
648         }
649     }
650 }