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