Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / DynamicExpression.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.Runtime.CompilerServices;
23
24 #if !FEATURE_CORE_DLR
25 namespace Microsoft.Scripting.Ast {
26 #else
27 namespace System.Linq.Expressions {
28 #endif
29     using Compiler;
30
31     /// <summary>
32     /// Represents a dynamic operation.
33     /// </summary>
34     [DebuggerTypeProxy(typeof(Expression.DynamicExpressionProxy))]
35     public class DynamicExpression : Expression, IArgumentProvider {
36         private readonly CallSiteBinder _binder;
37         private readonly Type _delegateType;
38
39         internal DynamicExpression(Type delegateType, CallSiteBinder binder) {
40             Debug.Assert(delegateType.GetMethod("Invoke").GetReturnType() == typeof(object) || GetType() != typeof(DynamicExpression));
41             _delegateType = delegateType;
42             _binder = binder;
43         }
44
45         internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, ReadOnlyCollection<Expression> arguments) {
46             if (returnType == typeof(object)) {
47                 return new DynamicExpressionN(delegateType, binder, arguments);
48             } else {
49                 return new TypedDynamicExpressionN(returnType, delegateType, binder, arguments);
50             }
51         }
52
53         internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0) {
54             if (returnType == typeof(object)) {
55                 return new DynamicExpression1(delegateType, binder, arg0);
56             } else {
57                 return new TypedDynamicExpression1(returnType, delegateType, binder, arg0);
58             }
59         }
60
61         internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) {
62             if (returnType == typeof(object)) {
63                 return new DynamicExpression2(delegateType, binder, arg0, arg1);
64             } else {
65                 return new TypedDynamicExpression2(returnType, delegateType, binder, arg0, arg1);
66             }
67         }
68
69         internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) {
70             if (returnType == typeof(object)) {
71                 return new DynamicExpression3(delegateType, binder, arg0, arg1, arg2);
72             } else {
73                 return new TypedDynamicExpression3(returnType, delegateType, binder, arg0, arg1, arg2);
74             }
75         }
76
77         internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
78             if (returnType == typeof(object)) {
79                 return new DynamicExpression4(delegateType, binder, arg0, arg1, arg2, arg3);
80             } else {
81                 return new TypedDynamicExpression4(returnType, delegateType, binder, arg0, arg1, arg2, arg3);
82             }
83         }
84
85         /// <summary>
86         /// Gets the static type of the expression that this <see cref="Expression" /> represents.
87         /// </summary>
88         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
89         public override Type Type {
90             get { return typeof(object); }
91         }
92
93         /// <summary>
94         /// Returns the node type of this Expression. Extension nodes should return
95         /// ExpressionType.Extension when overriding this method.
96         /// </summary>
97         /// <returns>The <see cref="ExpressionType"/> of the expression.</returns>
98         public sealed override ExpressionType NodeType {
99             get { return ExpressionType.Dynamic; }
100         }
101
102         /// <summary>
103         /// Gets the <see cref="CallSiteBinder" />, which determines the runtime behavior of the
104         /// dynamic site.
105         /// </summary>
106         public CallSiteBinder Binder {
107             get { return _binder; }
108         }
109
110         /// <summary>
111         /// Gets the type of the delegate used by the <see cref="CallSite" />.
112         /// </summary>
113         public Type DelegateType {
114             get { return _delegateType; }
115         }
116
117         /// <summary>
118         /// Gets the arguments to the dynamic operation.
119         /// </summary>
120         public ReadOnlyCollection<Expression> Arguments {
121             get { return GetOrMakeArguments(); }
122         }
123
124         internal virtual ReadOnlyCollection<Expression> GetOrMakeArguments() {
125             throw ContractUtils.Unreachable;
126         }
127
128         /// <summary>
129         /// Dispatches to the specific visit method for this node type.
130         /// </summary>
131         protected internal override Expression Accept(ExpressionVisitor visitor) {
132             return visitor.VisitDynamic(this);
133         }
134
135         /// <summary>
136         /// Makes a copy of this node replacing the args with the provided values.  The 
137         /// number of the args needs to match the number of the current block.
138         /// 
139         /// This helper is provided to allow re-writing of nodes to not depend on the specific optimized
140         /// subclass of DynamicExpression which is being used. 
141         /// </summary>
142         internal virtual DynamicExpression Rewrite(Expression[] args) {
143             throw ContractUtils.Unreachable;
144         }
145
146         /// <summary>
147         /// Creates a new expression that is like this one, but using the
148         /// supplied children. If all of the children are the same, it will
149         /// return this expression.
150         /// </summary>
151         /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
152         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
153         public DynamicExpression Update(IEnumerable<Expression> arguments) {
154             if (arguments == Arguments) {
155                 return this;
156             }
157
158             return Expression.MakeDynamic(DelegateType, Binder, arguments);
159         }
160
161         #region IArgumentProvider Members
162
163         Expression IArgumentProvider.GetArgument(int index) {
164             throw ContractUtils.Unreachable;
165         }
166
167         int IArgumentProvider.ArgumentCount {
168             get { throw ContractUtils.Unreachable; }
169         }
170
171         #endregion
172     }
173
174     #region Specialized Subclasses
175
176     internal class DynamicExpressionN : DynamicExpression, IArgumentProvider {
177         private IList<Expression> _arguments;       // storage for the original IList or readonly collection.  See IArgumentProvider for more info.
178
179         internal DynamicExpressionN(Type delegateType, CallSiteBinder binder, IList<Expression> arguments)
180             : base(delegateType, binder) {
181             _arguments = arguments;
182         }
183
184         Expression IArgumentProvider.GetArgument(int index) {
185             return _arguments[index];
186         }
187
188         int IArgumentProvider.ArgumentCount {
189             get {
190                 return _arguments.Count;
191             }
192         }
193
194         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
195             return ReturnReadOnly(ref _arguments);
196         }
197
198         internal override DynamicExpression Rewrite(Expression[] args) {
199             Debug.Assert(args.Length == ((IArgumentProvider)this).ArgumentCount);
200
201             return Expression.MakeDynamic(DelegateType, Binder, args);
202         }
203     }
204
205     internal class TypedDynamicExpressionN : DynamicExpressionN {
206         private readonly Type _returnType;
207
208         internal TypedDynamicExpressionN(Type returnType, Type delegateType, CallSiteBinder binder, IList<Expression> arguments)
209             : base(delegateType, binder, arguments) {
210             Debug.Assert(delegateType.GetMethod("Invoke").GetReturnType() == returnType);
211             _returnType = returnType;
212         }
213
214         public sealed override Type Type {
215             get { return _returnType; }
216         }
217     }
218
219     internal class DynamicExpression1 : DynamicExpression, IArgumentProvider {
220         private object _arg0;               // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
221
222         internal DynamicExpression1(Type delegateType, CallSiteBinder binder, Expression arg0)
223             : base(delegateType, binder) {
224             _arg0 = arg0;
225         }
226
227         Expression IArgumentProvider.GetArgument(int index) {
228             switch (index) {
229                 case 0: return ReturnObject<Expression>(_arg0);
230                 default: throw new InvalidOperationException();
231             }
232         }
233
234         int IArgumentProvider.ArgumentCount {
235             get {
236                 return 1;
237             }
238         }
239
240         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
241             return ReturnReadOnly(this, ref _arg0);
242         }
243
244         internal override DynamicExpression Rewrite(Expression[] args) {
245             Debug.Assert(args.Length == 1);
246
247             return Expression.MakeDynamic(DelegateType, Binder, args[0]);
248         }
249     }
250
251     internal sealed class TypedDynamicExpression1 : DynamicExpression1 {
252         private readonly Type _retType;
253
254         internal TypedDynamicExpression1(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0)
255             : base(delegateType, binder, arg0) {
256             _retType = retType;
257         }
258
259         public sealed override Type Type {
260             get { return _retType; }
261         }
262     }
263
264     internal class DynamicExpression2 : DynamicExpression, IArgumentProvider {
265         private object _arg0;                   // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
266         private readonly Expression _arg1;      // storage for the 2nd argument
267
268         internal DynamicExpression2(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1)
269             : base(delegateType, binder) {
270             _arg0 = arg0;
271             _arg1 = arg1;
272         }
273
274         Expression IArgumentProvider.GetArgument(int index) {
275             switch (index) {
276                 case 0: return ReturnObject<Expression>(_arg0);
277                 case 1: return _arg1;
278                 default: throw new InvalidOperationException();
279             }
280         }
281
282         int IArgumentProvider.ArgumentCount {
283             get {
284                 return 2;
285             }
286         }
287
288         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
289             return ReturnReadOnly(this, ref _arg0);
290         }
291
292         internal override DynamicExpression Rewrite(Expression[] args) {
293             Debug.Assert(args.Length == 2);
294
295             return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1]);
296         }
297     }
298
299     internal sealed class TypedDynamicExpression2 : DynamicExpression2 {
300         private readonly Type _retType;
301
302         internal TypedDynamicExpression2(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1)
303             : base(delegateType, binder, arg0, arg1) {
304             _retType = retType;
305         }
306
307         public sealed override Type Type {
308             get { return _retType; }
309         }
310     }
311
312     internal class DynamicExpression3 : DynamicExpression, IArgumentProvider {
313         private object _arg0;                       // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
314         private readonly Expression _arg1, _arg2;   // storage for the 2nd & 3rd arguments
315
316         internal DynamicExpression3(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2)
317             : base(delegateType, binder) {
318             _arg0 = arg0;
319             _arg1 = arg1;
320             _arg2 = arg2;
321         }
322
323         Expression IArgumentProvider.GetArgument(int index) {
324             switch (index) {
325                 case 0: return ReturnObject<Expression>(_arg0);
326                 case 1: return _arg1;
327                 case 2: return _arg2;
328                 default: throw new InvalidOperationException();
329             }
330         }
331
332         int IArgumentProvider.ArgumentCount {
333             get {
334                 return 3;
335             }
336         }
337
338         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
339             return ReturnReadOnly(this, ref _arg0);
340         }
341
342         internal override DynamicExpression Rewrite(Expression[] args) {
343             Debug.Assert(args.Length == 3);
344
345             return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1], args[2]);
346         }
347     }
348
349     internal sealed class TypedDynamicExpression3 : DynamicExpression3 {
350         private readonly Type _retType;
351
352         internal TypedDynamicExpression3(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2)
353             : base(delegateType, binder, arg0, arg1, arg2) {
354             _retType = retType;
355         }
356
357         public sealed override Type Type {
358             get { return _retType; }
359         }
360     }
361
362     internal class DynamicExpression4 : DynamicExpression, IArgumentProvider {
363         private object _arg0;                               // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
364         private readonly Expression _arg1, _arg2, _arg3;    // storage for the 2nd - 4th arguments
365
366         internal DynamicExpression4(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3)
367             : base(delegateType, binder) {
368             _arg0 = arg0;
369             _arg1 = arg1;
370             _arg2 = arg2;
371             _arg3 = arg3;
372         }
373
374         Expression IArgumentProvider.GetArgument(int index) {
375             switch (index) {
376                 case 0: return ReturnObject<Expression>(_arg0);
377                 case 1: return _arg1;
378                 case 2: return _arg2;
379                 case 3: return _arg3;
380                 default: throw new InvalidOperationException();
381             }
382         }
383
384         int IArgumentProvider.ArgumentCount {
385             get {
386                 return 4;
387             }
388         }
389
390         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
391             return ReturnReadOnly(this, ref _arg0);
392         }
393
394         internal override DynamicExpression Rewrite(Expression[] args) {
395             Debug.Assert(args.Length == 4);
396
397             return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1], args[2], args[3]);
398         }
399     }
400
401     internal sealed class TypedDynamicExpression4 : DynamicExpression4 {
402         private readonly Type _retType;
403
404         internal TypedDynamicExpression4(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3)
405             : base(delegateType, binder, arg0, arg1, arg2, arg3) {
406             _retType = retType;
407         }
408
409         public sealed override Type Type {
410             get { return _retType; }
411         }
412     }
413
414     #endregion
415
416     public partial class Expression {
417
418         /// <summary>
419         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
420         /// </summary>
421         /// <param name="delegateType">The type of the delegate used by the <see cref="CallSite" />.</param>
422         /// <param name="binder">The runtime binder for the dynamic operation.</param>
423         /// <param name="arguments">The arguments to the dynamic operation.</param>
424         /// <returns>
425         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
426         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
427         /// <see cref="DynamicExpression.DelegateType">DelegateType</see>,
428         /// <see cref="DynamicExpression.Binder">Binder</see>, and
429         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
430         /// </returns>
431         public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, params Expression[] arguments) {
432             return MakeDynamic(delegateType, binder, (IEnumerable<Expression>)arguments);
433         }
434
435         /// <summary>
436         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
437         /// </summary>
438         /// <param name="delegateType">The type of the delegate used by the <see cref="CallSite" />.</param>
439         /// <param name="binder">The runtime binder for the dynamic operation.</param>
440         /// <param name="arguments">The arguments to the dynamic operation.</param>
441         /// <returns>
442         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
443         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
444         /// <see cref="DynamicExpression.DelegateType">DelegateType</see>,
445         /// <see cref="DynamicExpression.Binder">Binder</see>, and
446         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
447         /// </returns>
448         public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, IEnumerable<Expression> arguments) {
449             ContractUtils.RequiresNotNull(delegateType, "delegateType");
450             ContractUtils.RequiresNotNull(binder, "binder");
451             if (!delegateType.IsSubclassOf(typeof(MulticastDelegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
452
453             var method = GetValidMethodForDynamic(delegateType);
454
455             var args = arguments.ToReadOnly();
456             ValidateArgumentTypes(method, ExpressionType.Dynamic, ref args);
457
458             return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, args);
459         }
460
461         /// <summary>
462         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" /> and one argument.
463         /// </summary>
464         /// <param name="delegateType">The type of the delegate used by the <see cref="CallSite" />.</param>
465         /// <param name="binder">The runtime binder for the dynamic operation.</param>
466         /// <param name="arg0">The argument to the dynamic operation.</param>
467         /// <returns>
468         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
469         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
470         /// <see cref="DynamicExpression.DelegateType">DelegateType</see>,
471         /// <see cref="DynamicExpression.Binder">Binder</see>, and
472         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
473         /// </returns>
474         public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0) {
475             ContractUtils.RequiresNotNull(delegateType, "delegateType");
476             ContractUtils.RequiresNotNull(binder, "binder");
477             if (!delegateType.IsSubclassOf(typeof(MulticastDelegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
478
479             var method = GetValidMethodForDynamic(delegateType);
480             var parameters = method.GetParametersCached();
481
482             ValidateArgumentCount(method, ExpressionType.Dynamic, 2, parameters);
483             ValidateDynamicArgument(arg0);
484             ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
485
486             return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0);
487         }
488
489         /// <summary>
490         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" /> and two arguments.
491         /// </summary>
492         /// <param name="delegateType">The type of the delegate used by the <see cref="CallSite" />.</param>
493         /// <param name="binder">The runtime binder for the dynamic operation.</param>
494         /// <param name="arg0">The first argument to the dynamic operation.</param>
495         /// <param name="arg1">The second argument to the dynamic operation.</param>
496         /// <returns>
497         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
498         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
499         /// <see cref="DynamicExpression.DelegateType">DelegateType</see>,
500         /// <see cref="DynamicExpression.Binder">Binder</see>, and
501         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
502         /// </returns>
503         public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) {
504             ContractUtils.RequiresNotNull(delegateType, "delegateType");
505             ContractUtils.RequiresNotNull(binder, "binder");
506             if (!delegateType.IsSubclassOf(typeof(MulticastDelegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
507
508             var method = GetValidMethodForDynamic(delegateType);
509             var parameters = method.GetParametersCached();
510
511             ValidateArgumentCount(method, ExpressionType.Dynamic, 3, parameters);
512             ValidateDynamicArgument(arg0);
513             ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
514             ValidateDynamicArgument(arg1);
515             ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]);
516
517             return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1);
518         }
519
520         /// <summary>
521         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" /> and three arguments.
522         /// </summary>
523         /// <param name="delegateType">The type of the delegate used by the <see cref="CallSite" />.</param>
524         /// <param name="binder">The runtime binder for the dynamic operation.</param>
525         /// <param name="arg0">The first argument to the dynamic operation.</param>
526         /// <param name="arg1">The second argument to the dynamic operation.</param>
527         /// <param name="arg2">The third argument to the dynamic operation.</param>
528         /// <returns>
529         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
530         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
531         /// <see cref="DynamicExpression.DelegateType">DelegateType</see>,
532         /// <see cref="DynamicExpression.Binder">Binder</see>, and
533         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
534         /// </returns>
535         public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) {
536             ContractUtils.RequiresNotNull(delegateType, "delegateType");
537             ContractUtils.RequiresNotNull(binder, "binder");
538             if (!delegateType.IsSubclassOf(typeof(MulticastDelegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
539
540             var method = GetValidMethodForDynamic(delegateType);
541             var parameters = method.GetParametersCached();
542
543             ValidateArgumentCount(method, ExpressionType.Dynamic, 4, parameters);
544             ValidateDynamicArgument(arg0);
545             ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
546             ValidateDynamicArgument(arg1);
547             ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]);
548             ValidateDynamicArgument(arg2);
549             ValidateOneArgument(method, ExpressionType.Dynamic, arg2, parameters[3]);
550
551             return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1, arg2);
552         }
553
554         /// <summary>
555         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" /> and four arguments.
556         /// </summary>
557         /// <param name="delegateType">The type of the delegate used by the <see cref="CallSite" />.</param>
558         /// <param name="binder">The runtime binder for the dynamic operation.</param>
559         /// <param name="arg0">The first argument to the dynamic operation.</param>
560         /// <param name="arg1">The second argument to the dynamic operation.</param>
561         /// <param name="arg2">The third argument to the dynamic operation.</param>
562         /// <param name="arg3">The fourth argument to the dynamic operation.</param>
563         /// <returns>
564         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
565         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
566         /// <see cref="DynamicExpression.DelegateType">DelegateType</see>,
567         /// <see cref="DynamicExpression.Binder">Binder</see>, and
568         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
569         /// </returns>
570         public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
571             ContractUtils.RequiresNotNull(delegateType, "delegateType");
572             ContractUtils.RequiresNotNull(binder, "binder");
573             if (!delegateType.IsSubclassOf(typeof(MulticastDelegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
574
575             var method = GetValidMethodForDynamic(delegateType);
576             var parameters = method.GetParametersCached();
577
578             ValidateArgumentCount(method, ExpressionType.Dynamic, 5, parameters);
579             ValidateDynamicArgument(arg0);
580             ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
581             ValidateDynamicArgument(arg1);
582             ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]);
583             ValidateDynamicArgument(arg2);
584             ValidateOneArgument(method, ExpressionType.Dynamic, arg2, parameters[3]);
585             ValidateDynamicArgument(arg3);
586             ValidateOneArgument(method, ExpressionType.Dynamic, arg3, parameters[4]);
587
588             return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1, arg2, arg3);
589         }
590
591         private static MethodInfo GetValidMethodForDynamic(Type delegateType) {
592             var method = delegateType.GetMethod("Invoke");
593             var pi = method.GetParametersCached();
594             if (pi.Length == 0 || pi[0].ParameterType != typeof(CallSite)) throw Error.FirstArgumentMustBeCallSite();
595             return method;
596         }
597
598         /// <summary>
599         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
600         /// </summary>
601         /// <param name="binder">The runtime binder for the dynamic operation.</param>
602         /// <param name="returnType">The result type of the dynamic expression.</param>
603         /// <param name="arguments">The arguments to the dynamic operation.</param>
604         /// <returns>
605         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
606         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
607         /// <see cref="DynamicExpression.Binder">Binder</see> and
608         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
609         /// </returns>
610         /// <remarks>
611         /// The <see cref="DynamicExpression.DelegateType">DelegateType</see> property of the
612         /// result will be inferred from the types of the arguments and the specified return type.
613         /// </remarks>
614         public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, params Expression[] arguments) {
615             return Dynamic(binder, returnType, (IEnumerable<Expression>)arguments);
616         }
617
618         /// <summary>
619         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
620         /// </summary>
621         /// <param name="binder">The runtime binder for the dynamic operation.</param>
622         /// <param name="returnType">The result type of the dynamic expression.</param>
623         /// <param name="arg0">The first argument to the dynamic operation.</param>
624         /// <returns>
625         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
626         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
627         /// <see cref="DynamicExpression.Binder">Binder</see> and
628         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
629         /// </returns>
630         /// <remarks>
631         /// The <see cref="DynamicExpression.DelegateType">DelegateType</see> property of the
632         /// result will be inferred from the types of the arguments and the specified return type.
633         /// </remarks>
634         public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0) {
635             ContractUtils.RequiresNotNull(binder, "binder");
636             ValidateDynamicArgument(arg0);
637
638             DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo(
639                 returnType,
640                 DelegateHelpers.GetNextTypeInfo(
641                     arg0.Type,
642                     DelegateHelpers.NextTypeInfo(typeof(CallSite))
643                 )
644             );
645
646             Type delegateType = info.DelegateType;
647             if (delegateType == null) {
648                 delegateType = info.MakeDelegateType(returnType, arg0);
649             }
650
651             return DynamicExpression.Make(returnType, delegateType, binder, arg0);
652         }
653
654         /// <summary>
655         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
656         /// </summary>
657         /// <param name="binder">The runtime binder for the dynamic operation.</param>
658         /// <param name="returnType">The result type of the dynamic expression.</param>
659         /// <param name="arg0">The first argument to the dynamic operation.</param>
660         /// <param name="arg1">The second argument to the dynamic operation.</param>
661         /// <returns>
662         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
663         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
664         /// <see cref="DynamicExpression.Binder">Binder</see> and
665         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
666         /// </returns>
667         /// <remarks>
668         /// The <see cref="DynamicExpression.DelegateType">DelegateType</see> property of the
669         /// result will be inferred from the types of the arguments and the specified return type.
670         /// </remarks>
671         public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1) {
672             ContractUtils.RequiresNotNull(binder, "binder");
673             ValidateDynamicArgument(arg0);
674             ValidateDynamicArgument(arg1);
675
676             DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo(
677                 returnType,
678                 DelegateHelpers.GetNextTypeInfo(
679                     arg1.Type,
680                     DelegateHelpers.GetNextTypeInfo(
681                         arg0.Type,
682                         DelegateHelpers.NextTypeInfo(typeof(CallSite))
683                     )
684                 )
685             );
686
687             Type delegateType = info.DelegateType;
688             if (delegateType == null) {
689                 delegateType = info.MakeDelegateType(returnType, arg0, arg1);
690             }
691
692             return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1);
693         }
694
695         /// <summary>
696         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
697         /// </summary>
698         /// <param name="binder">The runtime binder for the dynamic operation.</param>
699         /// <param name="returnType">The result type of the dynamic expression.</param>
700         /// <param name="arg0">The first argument to the dynamic operation.</param>
701         /// <param name="arg1">The second argument to the dynamic operation.</param>
702         /// <param name="arg2">The third argument to the dynamic operation.</param>
703         /// <returns>
704         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
705         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
706         /// <see cref="DynamicExpression.Binder">Binder</see> and
707         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
708         /// </returns>
709         /// <remarks>
710         /// The <see cref="DynamicExpression.DelegateType">DelegateType</see> property of the
711         /// result will be inferred from the types of the arguments and the specified return type.
712         /// </remarks>
713         public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1, Expression arg2) {
714             ContractUtils.RequiresNotNull(binder, "binder");
715             ValidateDynamicArgument(arg0);
716             ValidateDynamicArgument(arg1);
717             ValidateDynamicArgument(arg2);
718
719             DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo(
720                 returnType,
721                 DelegateHelpers.GetNextTypeInfo(
722                     arg2.Type,
723                     DelegateHelpers.GetNextTypeInfo(
724                         arg1.Type,
725                         DelegateHelpers.GetNextTypeInfo(
726                             arg0.Type,
727                             DelegateHelpers.NextTypeInfo(typeof(CallSite))
728                         )
729                     )
730                 )
731             );
732
733             Type delegateType = info.DelegateType;
734             if (delegateType == null) {
735                 delegateType = info.MakeDelegateType(returnType, arg0, arg1, arg2);
736             }
737
738             return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1, arg2);
739         }
740
741         /// <summary>
742         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
743         /// </summary>
744         /// <param name="binder">The runtime binder for the dynamic operation.</param>
745         /// <param name="returnType">The result type of the dynamic expression.</param>
746         /// <param name="arg0">The first argument to the dynamic operation.</param>
747         /// <param name="arg1">The second argument to the dynamic operation.</param>
748         /// <param name="arg2">The third argument to the dynamic operation.</param>
749         /// <param name="arg3">The fourth argument to the dynamic operation.</param>
750         /// <returns>
751         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
752         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
753         /// <see cref="DynamicExpression.Binder">Binder</see> and
754         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
755         /// </returns>
756         /// <remarks>
757         /// The <see cref="DynamicExpression.DelegateType">DelegateType</see> property of the
758         /// result will be inferred from the types of the arguments and the specified return type.
759         /// </remarks>
760         public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
761             ContractUtils.RequiresNotNull(binder, "binder");
762             ValidateDynamicArgument(arg0);
763             ValidateDynamicArgument(arg1);
764             ValidateDynamicArgument(arg2);
765             ValidateDynamicArgument(arg3);
766
767             DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo(
768                 returnType,
769                 DelegateHelpers.GetNextTypeInfo(
770                     arg3.Type,
771                     DelegateHelpers.GetNextTypeInfo(
772                         arg2.Type,
773                         DelegateHelpers.GetNextTypeInfo(
774                             arg1.Type,
775                             DelegateHelpers.GetNextTypeInfo(
776                                 arg0.Type,
777                                 DelegateHelpers.NextTypeInfo(typeof(CallSite))
778                             )
779                         )
780                     )
781                 )
782             );
783
784             Type delegateType = info.DelegateType;
785             if (delegateType == null) {
786                 delegateType = info.MakeDelegateType(returnType, arg0, arg1, arg2, arg3);
787             }
788
789             return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1, arg2, arg3);
790         }
791
792         /// <summary>
793         /// Creates a <see cref="DynamicExpression" /> that represents a dynamic operation bound by the provided <see cref="CallSiteBinder" />.
794         /// </summary>
795         /// <param name="binder">The runtime binder for the dynamic operation.</param>
796         /// <param name="returnType">The result type of the dynamic expression.</param>
797         /// <param name="arguments">The arguments to the dynamic operation.</param>
798         /// <returns>
799         /// A <see cref="DynamicExpression" /> that has <see cref="NodeType" /> equal to
800         /// <see cref="ExpressionType.Dynamic">Dynamic</see> and has the
801         /// <see cref="DynamicExpression.Binder">Binder</see> and
802         /// <see cref="DynamicExpression.Arguments">Arguments</see> set to the specified values.
803         /// </returns>
804         /// <remarks>
805         /// The <see cref="DynamicExpression.DelegateType">DelegateType</see> property of the
806         /// result will be inferred from the types of the arguments and the specified return type.
807         /// </remarks>
808         public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, IEnumerable<Expression> arguments) {
809             ContractUtils.RequiresNotNull(arguments, "arguments");
810             ContractUtils.RequiresNotNull(returnType, "returnType");
811
812             var args = arguments.ToReadOnly();
813             ContractUtils.RequiresNotEmpty(args, "args");
814             return MakeDynamic(binder, returnType, args);
815         }
816
817         private static DynamicExpression MakeDynamic(CallSiteBinder binder, Type returnType, ReadOnlyCollection<Expression> args) {
818             ContractUtils.RequiresNotNull(binder, "binder");
819
820             for (int i = 0; i < args.Count; i++) {
821                 Expression arg = args[i];
822
823                 ValidateDynamicArgument(arg);
824             }
825
826             Type delegateType = DelegateHelpers.MakeCallSiteDelegate(args, returnType);
827
828             // Since we made a delegate with argument types that exactly match,
829             // we can skip delegate and argument validation
830
831             switch (args.Count) {
832                 case 1: return DynamicExpression.Make(returnType, delegateType, binder, args[0]);
833                 case 2: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1]);
834                 case 3: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1], args[2]);
835                 case 4: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1], args[2], args[3]);
836                 default: return DynamicExpression.Make(returnType, delegateType, binder, args);
837             }
838         }
839
840         private static void ValidateDynamicArgument(Expression arg) {
841             RequiresCanRead(arg, "arguments");
842             var type = arg.Type;
843             ContractUtils.RequiresNotNull(type, "type");
844             TypeUtils.ValidateType(type);
845             if (type == typeof(void)) throw Error.ArgumentTypeCannotBeVoid();
846         }
847     }
848 }