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