Facilitate the merge
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / MethodCallExpression.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. 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  Microsoft Public License, 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 Microsoft Public License.
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 SILVERLIGHT
25 using System.Core;
26 #endif
27
28 #if CLR2
29 namespace Microsoft.Scripting.Ast {
30 #else
31 namespace System.Linq.Expressions {
32 #endif
33     /// <summary>
34     /// Represents a call to either static or an instance method.
35     /// </summary>
36 #if !SILVERLIGHT
37     [DebuggerTypeProxy(typeof(Expression.MethodCallExpressionProxy))]
38 #endif
39     public class MethodCallExpression : Expression, IArgumentProvider {
40         private readonly MethodInfo _method;
41
42         internal MethodCallExpression(MethodInfo method) {
43
44             _method = method;
45         }
46
47         internal virtual Expression GetInstance() {
48             return null;
49         }
50
51         /// <summary>
52         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
53         /// </summary>
54         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
55         public sealed override ExpressionType NodeType {
56             get { return ExpressionType.Call; }
57         }
58
59         /// <summary>
60         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
61         /// </summary>
62         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
63         public sealed override Type Type {
64             get { return _method.ReturnType; }
65         }
66
67         /// <summary>
68         /// Gets the <see cref="MethodInfo" /> for the method to be called.
69         /// </summary>
70         public MethodInfo Method {
71             get { return _method; }
72         }
73
74         /// <summary>
75         /// Gets the <see cref="Expression" /> that represents the instance 
76         /// for instance method calls or null for static method cals.
77         /// </summary>
78         public Expression Object {
79             get { return GetInstance(); }
80         }
81
82         /// <summary>
83         /// Gets a collection of expressions that represent arguments to the method call.
84         /// </summary>
85         public ReadOnlyCollection<Expression> Arguments {
86             get { return GetOrMakeArguments(); }
87         }
88
89         /// <summary>
90         /// Creates a new expression that is like this one, but using the
91         /// supplied children. If all of the children are the same, it will
92         /// return this expression.
93         /// </summary>
94         /// <param name="object">The <see cref="Object" /> property of the result.</param>
95         /// <param name="arguments">The <see cref="Arguments" /> property of the result.</param>
96         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
97         public MethodCallExpression Update(Expression @object, IEnumerable<Expression> arguments) {
98             if (@object == Object && arguments == Arguments) {
99                 return this;
100             }
101             return Expression.Call(@object, Method, arguments);
102         }
103
104         internal virtual ReadOnlyCollection<Expression> GetOrMakeArguments() {
105             throw ContractUtils.Unreachable;
106         }
107
108         /// <summary>
109         /// Dispatches to the specific visit method for this node type.
110         /// </summary>
111         protected internal override Expression Accept(ExpressionVisitor visitor) {
112             return visitor.VisitMethodCall(this);
113         }
114
115         /// <summary>
116         /// Returns a new MethodCallExpression replacing the existing instance/args with the
117         /// newly provided instance and args.    Arguments can be null to use the existing
118         /// arguments.
119         /// 
120         /// This helper is provided to allow re-writing of nodes to not depend on the specific optimized
121         /// subclass of MethodCallExpression which is being used. 
122         /// </summary>
123         internal virtual MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
124             throw ContractUtils.Unreachable;
125         }
126
127         #region IArgumentProvider Members
128
129         Expression IArgumentProvider.GetArgument(int index) {
130             throw ContractUtils.Unreachable;
131         }
132
133         int IArgumentProvider.ArgumentCount {
134             get { throw ContractUtils.Unreachable; }
135         }
136
137         #endregion
138     }
139
140     #region Specialized Subclasses
141
142     internal class MethodCallExpressionN : MethodCallExpression, IArgumentProvider {
143         private IList<Expression> _arguments;
144
145         public MethodCallExpressionN(MethodInfo method, IList<Expression> args)
146             : base(method) {
147             _arguments = args;
148         }
149
150         Expression IArgumentProvider.GetArgument(int index) {
151             return _arguments[index];
152         }
153
154         int IArgumentProvider.ArgumentCount {
155             get {
156                 return _arguments.Count;
157             }
158         }
159
160         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
161             return ReturnReadOnly(ref _arguments);
162         }
163
164         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
165             Debug.Assert(instance == null);
166             Debug.Assert(args == null || args.Count == _arguments.Count);
167
168             return Expression.Call(Method, args ?? _arguments);
169         }
170     }
171
172     internal class InstanceMethodCallExpressionN : MethodCallExpression, IArgumentProvider {
173         private IList<Expression> _arguments;
174         private readonly Expression _instance;
175
176         public InstanceMethodCallExpressionN(MethodInfo method, Expression instance, IList<Expression> args)
177             : base(method) {
178             _instance = instance;
179             _arguments = args;
180         }
181
182         Expression IArgumentProvider.GetArgument(int index) {
183             return _arguments[index];
184         }
185
186         int IArgumentProvider.ArgumentCount {
187             get {
188                 return _arguments.Count;
189             }
190         }
191
192         internal override Expression GetInstance() {
193             return _instance;
194         }
195
196         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
197             return ReturnReadOnly(ref _arguments);
198         }
199
200         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
201             Debug.Assert(instance != null);
202             Debug.Assert(args == null || args.Count == _arguments.Count);
203
204             return Expression.Call(instance, Method, args ?? _arguments);
205         }
206     }
207
208     internal class MethodCallExpression1 : MethodCallExpression, IArgumentProvider {
209         private object _arg0;       // storage for the 1st argument or a readonly collection.  See IArgumentProvider
210
211         public MethodCallExpression1(MethodInfo method, Expression arg0)
212             : base(method) {
213             _arg0 = arg0;
214         }
215
216         Expression IArgumentProvider.GetArgument(int index) {
217             switch (index) {
218                 case 0: return ReturnObject<Expression>(_arg0);
219                 default: throw new InvalidOperationException();
220             }
221         }
222
223         int IArgumentProvider.ArgumentCount {
224             get {
225                 return 1;
226             }
227         }
228
229         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
230             return ReturnReadOnly(this, ref _arg0);
231         }
232
233         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
234             Debug.Assert(instance == null);
235             Debug.Assert(args == null || args.Count == 1);
236
237             if (args != null) {
238                 return Expression.Call(Method, args[0]);
239             }
240
241             return Expression.Call(Method, ReturnObject<Expression>(_arg0));
242         }
243     }
244
245     internal class MethodCallExpression2 : MethodCallExpression, IArgumentProvider {
246         private object _arg0;               // storage for the 1st argument or a readonly collection.  See IArgumentProvider
247         private readonly Expression _arg1;  // storage for the 2nd arg
248
249         public MethodCallExpression2(MethodInfo method, Expression arg0, Expression arg1)
250             : base(method) {
251             _arg0 = arg0;
252             _arg1 = arg1;
253         }
254
255         Expression IArgumentProvider.GetArgument(int index) {
256             switch (index) {
257                 case 0: return ReturnObject<Expression>(_arg0);
258                 case 1: return _arg1;
259                 default: throw new InvalidOperationException();
260             }
261         }
262
263         int IArgumentProvider.ArgumentCount {
264             get {
265                 return 2;
266             }
267         }
268
269         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
270             return ReturnReadOnly(this, ref _arg0);
271         }
272
273         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
274             Debug.Assert(instance == null);
275             Debug.Assert(args == null || args.Count == 2);
276
277             if (args != null) {
278                 return Expression.Call(Method, args[0], args[1]);
279             }
280             return Expression.Call(Method, ReturnObject<Expression>(_arg0), _arg1);
281         }
282     }
283
284     internal class MethodCallExpression3 : MethodCallExpression, IArgumentProvider {
285         private object _arg0;           // storage for the 1st argument or a readonly collection.  See IArgumentProvider
286         private readonly Expression _arg1, _arg2; // storage for the 2nd - 3rd args.
287
288         public MethodCallExpression3(MethodInfo method, Expression arg0, Expression arg1, Expression arg2)
289             : base(method) {
290             _arg0 = arg0;
291             _arg1 = arg1;
292             _arg2 = arg2;
293         }
294
295         Expression IArgumentProvider.GetArgument(int index) {
296             switch (index) {
297                 case 0: return ReturnObject<Expression>(_arg0);
298                 case 1: return _arg1;
299                 case 2: return _arg2;
300                 default: throw new InvalidOperationException();
301             }
302         }
303
304         int IArgumentProvider.ArgumentCount {
305             get {
306                 return 3;
307             }
308         }
309
310         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
311             return ReturnReadOnly(this, ref _arg0);
312         }
313
314         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
315             Debug.Assert(instance == null);
316             Debug.Assert(args == null || args.Count == 3);
317
318             if (args != null) {
319                 return Expression.Call(Method, args[0], args[1], args[2]);
320             }
321             return Expression.Call(Method, ReturnObject<Expression>(_arg0), _arg1, _arg2);
322         }
323     }
324
325     internal class MethodCallExpression4 : MethodCallExpression, IArgumentProvider {
326         private object _arg0;               // storage for the 1st argument or a readonly collection.  See IArgumentProvider
327         private readonly Expression _arg1, _arg2, _arg3;  // storage for the 2nd - 4th args.
328
329         public MethodCallExpression4(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3)
330             : base(method) {
331             _arg0 = arg0;
332             _arg1 = arg1;
333             _arg2 = arg2;
334             _arg3 = arg3;
335         }
336
337         Expression IArgumentProvider.GetArgument(int index) {
338             switch (index) {
339                 case 0: return ReturnObject<Expression>(_arg0);
340                 case 1: return _arg1;
341                 case 2: return _arg2;
342                 case 3: return _arg3;
343                 default: throw new InvalidOperationException();
344             }
345         }
346
347         int IArgumentProvider.ArgumentCount {
348             get {
349                 return 4;
350             }
351         }
352
353         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
354             return ReturnReadOnly(this, ref _arg0);
355         }
356
357         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
358             Debug.Assert(instance == null);
359             Debug.Assert(args == null || args.Count == 4);
360
361             if (args != null) {
362                 return Expression.Call(Method, args[0], args[1], args[2], args[3]);
363             }
364             return Expression.Call(Method, ReturnObject<Expression>(_arg0), _arg1, _arg2, _arg3);
365         }
366     }
367
368     internal class MethodCallExpression5 : MethodCallExpression, IArgumentProvider {
369         private object _arg0;           // storage for the 1st argument or a readonly collection.  See IArgumentProvider
370         private readonly Expression _arg1, _arg2, _arg3, _arg4;   // storage for the 2nd - 5th args.
371
372         public MethodCallExpression5(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4)
373             : base(method) {
374             _arg0 = arg0;
375             _arg1 = arg1;
376             _arg2 = arg2;
377             _arg3 = arg3;
378             _arg4 = arg4;
379         }
380
381         Expression IArgumentProvider.GetArgument(int index) {
382             switch (index) {
383                 case 0: return ReturnObject<Expression>(_arg0);
384                 case 1: return _arg1;
385                 case 2: return _arg2;
386                 case 3: return _arg3;
387                 case 4: return _arg4;
388                 default: throw new InvalidOperationException();
389             }
390         }
391
392         int IArgumentProvider.ArgumentCount {
393             get {
394                 return 5;
395             }
396         }
397
398         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
399             return ReturnReadOnly(this, ref _arg0);
400         }
401
402         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
403             Debug.Assert(instance == null);
404             Debug.Assert(args == null || args.Count == 5);
405
406             if (args != null) {
407                 return Expression.Call(Method, args[0], args[1], args[2], args[3], args[4]);
408             }
409
410             return Expression.Call(Method, ReturnObject<Expression>(_arg0), _arg1, _arg2, _arg3, _arg4);
411         }
412     }
413
414     internal class InstanceMethodCallExpression2 : MethodCallExpression, IArgumentProvider {
415         private readonly Expression _instance;
416         private object _arg0;                // storage for the 1st argument or a readonly collection.  See IArgumentProvider
417         private readonly Expression _arg1;   // storage for the 2nd argument
418
419         public InstanceMethodCallExpression2(MethodInfo method, Expression instance, Expression arg0, Expression arg1)
420             : base(method) {
421             Debug.Assert(instance != null);
422
423             _instance = instance;
424             _arg0 = arg0;
425             _arg1 = arg1;
426         }
427
428         Expression IArgumentProvider.GetArgument(int index) {
429             switch (index) {
430                 case 0: return ReturnObject<Expression>(_arg0);
431                 case 1: return _arg1;
432                 default: throw new InvalidOperationException();
433             }
434         }
435
436         int IArgumentProvider.ArgumentCount {
437             get {
438                 return 2;
439             }
440         }
441
442         internal override Expression GetInstance() {
443             return _instance;
444         }
445
446         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
447             return ReturnReadOnly(this, ref _arg0);
448         }
449
450         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
451             Debug.Assert(instance != null);
452             Debug.Assert(args == null || args.Count == 2);
453
454             if (args != null) {
455                 return Expression.Call(instance, Method, args[0], args[1]);
456             }
457             return Expression.Call(instance, Method, ReturnObject<Expression>(_arg0), _arg1);
458         }
459     }
460
461     internal class InstanceMethodCallExpression3 : MethodCallExpression, IArgumentProvider {
462         private readonly Expression _instance;
463         private object _arg0;                       // storage for the 1st argument or a readonly collection.  See IArgumentProvider
464         private readonly Expression _arg1, _arg2;   // storage for the 2nd - 3rd argument
465
466         public InstanceMethodCallExpression3(MethodInfo method, Expression instance, Expression arg0, Expression arg1, Expression arg2)
467             : base(method) {
468             Debug.Assert(instance != null);
469
470             _instance = instance;
471             _arg0 = arg0;
472             _arg1 = arg1;
473             _arg2 = arg2;
474         }
475
476         Expression IArgumentProvider.GetArgument(int index) {
477             switch (index) {
478                 case 0: return ReturnObject<Expression>(_arg0);
479                 case 1: return _arg1;
480                 case 2: return _arg2;
481                 default: throw new InvalidOperationException();
482             }
483         }
484
485         int IArgumentProvider.ArgumentCount {
486             get {
487                 return 3;
488             }
489         }
490
491         internal override Expression GetInstance() {
492             return _instance;
493         }
494
495         internal override ReadOnlyCollection<Expression> GetOrMakeArguments() {
496             return ReturnReadOnly(this, ref _arg0);
497         }
498
499         internal override MethodCallExpression Rewrite(Expression instance, IList<Expression> args) {
500             Debug.Assert(instance != null);
501             Debug.Assert(args == null || args.Count == 3);
502
503             if (args != null) {
504                 return Expression.Call(instance, Method, args[0], args[1], args[2]);
505             }
506             return Expression.Call(instance, Method, ReturnObject<Expression>(_arg0), _arg1, _arg2);
507         }
508     }
509
510     #endregion
511
512     public partial class Expression {
513
514         #region Call
515
516         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a call to a static method that takes one argument.</summary>
517         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
518         ///<param name="method">A <see cref="T:System.Reflection.MethodInfo" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> property equal to.</param>
519         ///<param name="arg0">The <see cref="Expression" /> that represents the first argument.</param>
520         ///<exception cref="T:System.ArgumentNullException">
521         ///<paramref name="method" /> is null.</exception>
522         public static MethodCallExpression Call(MethodInfo method, Expression arg0) {
523             ContractUtils.RequiresNotNull(method, "method");
524             ContractUtils.RequiresNotNull(arg0, "arg0");
525
526             ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method);
527
528             ValidateArgumentCount(method, ExpressionType.Call, 1, pis);
529
530             arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
531
532             return new MethodCallExpression1(method, arg0);
533         }
534
535         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a call to a static method that takes two arguments.</summary>
536         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
537         ///<param name="method">A <see cref="T:System.Reflection.MethodInfo" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> property equal to.</param>
538         ///<param name="arg0">The <see cref="Expression" /> that represents the first argument.</param>
539         ///<param name="arg1">The <see cref="Expression" /> that represents the second argument.</param>
540         ///<exception cref="T:System.ArgumentNullException">
541         ///<paramref name="method" /> is null.</exception>
542         public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1) {
543             ContractUtils.RequiresNotNull(method, "method");
544             ContractUtils.RequiresNotNull(arg0, "arg0");
545             ContractUtils.RequiresNotNull(arg1, "arg1");
546
547             ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method);
548
549             ValidateArgumentCount(method, ExpressionType.Call, 2, pis);
550
551             arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
552             arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
553
554             return new MethodCallExpression2(method, arg0, arg1);
555         }
556
557         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a call to a static method that takes three arguments.</summary>
558         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
559         ///<param name="method">A <see cref="T:System.Reflection.MethodInfo" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> property equal to.</param>
560         ///<param name="arg0">The <see cref="Expression" /> that represents the first argument.</param>
561         ///<param name="arg1">The <see cref="Expression" /> that represents the second argument.</param>
562         ///<param name="arg2">The <see cref="Expression" /> that represents the third argument.</param>
563         ///<exception cref="T:System.ArgumentNullException">
564         ///<paramref name="method" /> is null.</exception>
565         public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1, Expression arg2) {
566             ContractUtils.RequiresNotNull(method, "method");
567             ContractUtils.RequiresNotNull(arg0, "arg0");
568             ContractUtils.RequiresNotNull(arg1, "arg1");
569             ContractUtils.RequiresNotNull(arg2, "arg2");
570
571             ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method);
572
573             ValidateArgumentCount(method, ExpressionType.Call, 3, pis);
574
575             arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
576             arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
577             arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]);
578
579             return new MethodCallExpression3(method, arg0, arg1, arg2);
580         }
581
582         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a call to a static method that takes four arguments.</summary>
583         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
584         ///<param name="method">A <see cref="T:System.Reflection.MethodInfo" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> property equal to.</param>
585         ///<param name="arg0">The <see cref="Expression" /> that represents the first argument.</param>
586         ///<param name="arg1">The <see cref="Expression" /> that represents the second argument.</param>
587         ///<param name="arg2">The <see cref="Expression" /> that represents the third argument.</param>
588         ///<param name="arg3">The <see cref="Expression" /> that represents the fourth argument.</param>
589         ///<exception cref="T:System.ArgumentNullException">
590         ///<paramref name="method" /> is null.</exception>
591         public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
592             ContractUtils.RequiresNotNull(method, "method");
593             ContractUtils.RequiresNotNull(arg0, "arg0");
594             ContractUtils.RequiresNotNull(arg1, "arg1");
595             ContractUtils.RequiresNotNull(arg2, "arg2");
596             ContractUtils.RequiresNotNull(arg3, "arg3");
597
598             ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method);
599
600             ValidateArgumentCount(method, ExpressionType.Call, 4, pis);
601
602             arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
603             arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
604             arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]);
605             arg3 = ValidateOneArgument(method, ExpressionType.Call, arg3, pis[3]);
606
607             return new MethodCallExpression4(method, arg0, arg1, arg2, arg3);
608         }
609
610         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a call to a static method that takes five arguments.</summary>
611         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
612         ///<param name="method">A <see cref="T:System.Reflection.MethodInfo" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> property equal to.</param>
613         ///<param name="arg0">The <see cref="Expression" /> that represents the first argument.</param>
614         ///<param name="arg1">The <see cref="Expression" /> that represents the second argument.</param>
615         ///<param name="arg2">The <see cref="Expression" /> that represents the third argument.</param>
616         ///<param name="arg3">The <see cref="Expression" /> that represents the fourth argument.</param>
617         ///<param name="arg4">The <see cref="Expression" /> that represents the fifth argument.</param>
618         ///<exception cref="T:System.ArgumentNullException">
619         ///<paramref name="method" /> is null.</exception>
620         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
621         public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) {
622             ContractUtils.RequiresNotNull(method, "method");
623             ContractUtils.RequiresNotNull(arg0, "arg0");
624             ContractUtils.RequiresNotNull(arg1, "arg1");
625             ContractUtils.RequiresNotNull(arg2, "arg2");
626             ContractUtils.RequiresNotNull(arg3, "arg3");
627             ContractUtils.RequiresNotNull(arg4, "arg4");
628
629             ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method);
630
631             ValidateArgumentCount(method, ExpressionType.Call, 5, pis);
632
633             arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
634             arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
635             arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]);
636             arg3 = ValidateOneArgument(method, ExpressionType.Call, arg3, pis[3]);
637             arg4 = ValidateOneArgument(method, ExpressionType.Call, arg4, pis[4]);
638
639             return new MethodCallExpression5(method, arg0, arg1, arg2, arg3, arg4);
640         }
641
642         /// <summary>
643         /// Creates a <see cref="MethodCallExpression" /> that represents a call to a static (Shared in Visual Basic) method.
644         /// </summary>
645         /// <param name="method">The <see cref="MethodInfo" /> that represents the target method.</param>
646         /// <param name="arguments">The array of one or more of <see cref="Expression" /> that represents the call arguments.</param>
647         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
648         public static MethodCallExpression Call(MethodInfo method, params Expression[] arguments) {
649             return Call(null, method, arguments);
650         }
651
652         /// <summary>
653         /// Creates a <see cref="MethodCallExpression" /> that represents a call to a static (Shared in Visual Basic) method.
654         /// </summary>
655         /// <param name="method">The <see cref="MethodInfo" /> that represents the target method.</param>
656         /// <param name="arguments">A collection of <see cref="Expression" /> that represents the call arguments.</param>
657         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
658         public static MethodCallExpression Call(MethodInfo method, IEnumerable<Expression> arguments) {
659             return Call(null, method, arguments);
660         }
661
662         /// <summary>
663         /// Creates a <see cref="MethodCallExpression" /> that represents a call to a method that takes no arguments.
664         /// </summary>
665         /// <param name="instance">An <see cref="Expression" /> that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).</param>
666         /// <param name="method">The <see cref="MethodInfo" /> that represents the target method.</param>
667         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
668         public static MethodCallExpression Call(Expression instance, MethodInfo method) {
669             return Call(instance, method, EmptyReadOnlyCollection<Expression>.Instance);
670         }
671
672         /// <summary>
673         /// Creates a <see cref="MethodCallExpression" /> that represents a method call.
674         /// </summary>
675         /// <param name="instance">An <see cref="Expression" /> that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).</param>
676         /// <param name="method">The <see cref="MethodInfo" /> that represents the target method.</param>
677         /// <param name="arguments">An array of one or more of <see cref="Expression" /> that represents the call arguments.</param>
678         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
679         public static MethodCallExpression Call(Expression instance, MethodInfo method, params Expression[] arguments) {
680             return Call(instance, method, (IEnumerable<Expression>)arguments);
681         }
682
683         /// <summary>
684         /// Creates a <see cref="MethodCallExpression" /> that represents a call to a method that takes two arguments.
685         /// </summary>
686         /// <param name="instance">An <see cref="Expression" /> that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).</param>
687         /// <param name="method">The <see cref="MethodInfo" /> that represents the target method.</param>
688         /// <param name="arg0">The <see cref="Expression" /> that represents the first argument.</param>
689         /// <param name="arg1">The <see cref="Expression" /> that represents the second argument.</param>
690         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
691         public static MethodCallExpression Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1) {
692             ContractUtils.RequiresNotNull(method, "method");
693             ContractUtils.RequiresNotNull(arg0, "arg0");
694             ContractUtils.RequiresNotNull(arg1, "arg1");
695
696             ParameterInfo[] pis = ValidateMethodAndGetParameters(instance, method);
697
698             ValidateArgumentCount(method, ExpressionType.Call, 2, pis);
699
700             arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
701             arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
702
703             if (instance != null) {
704                 return new InstanceMethodCallExpression2(method, instance, arg0, arg1);
705             }
706
707             return new MethodCallExpression2(method, arg0, arg1);
708         }
709
710         /// <summary>
711         /// Creates a <see cref="MethodCallExpression" /> that represents a call to a method that takes three arguments.
712         /// </summary>
713         /// <param name="instance">An <see cref="Expression" /> that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).</param>
714         /// <param name="method">The <see cref="MethodInfo" /> that represents the target method.</param>
715         /// <param name="arg0">The <see cref="Expression" /> that represents the first argument.</param>
716         /// <param name="arg1">The <see cref="Expression" /> that represents the second argument.</param>
717         /// <param name="arg2">The <see cref="Expression" /> that represents the third argument.</param>
718         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> properties set to the specified values.</returns>
719         public static MethodCallExpression Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1, Expression arg2) {
720             ContractUtils.RequiresNotNull(method, "method");
721             ContractUtils.RequiresNotNull(arg0, "arg0");
722             ContractUtils.RequiresNotNull(arg1, "arg1");
723             ContractUtils.RequiresNotNull(arg2, "arg2");
724
725             ParameterInfo[] pis = ValidateMethodAndGetParameters(instance, method);
726
727             ValidateArgumentCount(method, ExpressionType.Call, 3, pis);
728
729             arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
730             arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
731             arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]);
732
733             if (instance != null) {
734                 return new InstanceMethodCallExpression3(method, instance, arg0, arg1, arg2);
735             }
736             return new MethodCallExpression3(method, arg0, arg1, arg2);
737         }
738
739         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a call to an instance method by calling the appropriate factory method.</summary>
740         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" />, the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> property equal to <paramref name="instance" />, <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> set to the <see cref="T:System.Reflection.MethodInfo" /> that represents the specified instance method, and <see cref="P:System.Linq.Expressions.MethodCallExpression.Arguments" /> set to the specified arguments.</returns>
741         ///<param name="instance">An <see cref="T:System.Linq.Expressions.Expression" /> whose <see cref="P:System.Linq.Expressions.Expression.Type" /> property value will be searched for a specific method.</param>
742         ///<param name="methodName">The name of the method.</param>
743         ///<param name="typeArguments">
744         ///An array of <see cref="T:System.Type" /> objects that specify the type parameters of the generic method.
745         ///This argument should be null when <paramref name="methodName" /> specifies a non-generic method.
746         ///</param>
747         ///<param name="arguments">An array of <see cref="T:System.Linq.Expressions.Expression" /> objects that represents the arguments to the method.</param>
748         ///<exception cref="T:System.ArgumentNullException">
749         ///<paramref name="instance" /> or <paramref name="methodName" /> is null.</exception>
750         ///<exception cref="T:System.InvalidOperationException">No method whose name is <paramref name="methodName" />, whose type parameters match <paramref name="typeArguments" />, and whose parameter types match <paramref name="arguments" /> is found in <paramref name="instance" />.Type or its base types.-or-More than one method whose name is <paramref name="methodName" />, whose type parameters match <paramref name="typeArguments" />, and whose parameter types match <paramref name="arguments" /> is found in <paramref name="instance" />.Type or its base types.</exception>
751         public static MethodCallExpression Call(Expression instance, string methodName, Type[] typeArguments, params Expression[] arguments) {
752             ContractUtils.RequiresNotNull(instance, "instance");
753             ContractUtils.RequiresNotNull(methodName, "methodName");
754             if (arguments == null) {
755                 arguments = new Expression[0];
756             }
757
758             BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
759             return Expression.Call(instance, FindMethod(instance.Type, methodName, typeArguments, arguments, flags), arguments);
760         }
761
762         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a call to a static (Shared in Visual Basic) method by calling the appropriate factory method.</summary>
763         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" />, the <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> property set to the <see cref="T:System.Reflection.MethodInfo" /> that represents the specified static (Shared in Visual Basic) method, and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Arguments" /> property set to the specified arguments.</returns>
764         ///<param name="type">The <see cref="T:System.Type" /> that specifies the type that contains the specified static (Shared in Visual Basic) method.</param>
765         ///<param name="methodName">The name of the method.</param>
766         ///<param name="typeArguments">
767         ///An array of <see cref="T:System.Type" /> objects that specify the type parameters of the generic method.
768         ///This argument should be null when <paramref name="methodName" /> specifies a non-generic method.
769         ///</param>
770         ///<param name="arguments">An array of <see cref="T:System.Linq.Expressions.Expression" /> objects that represent the arguments to the method.</param>
771         ///<exception cref="T:System.ArgumentNullException">
772         ///<paramref name="type" /> or <paramref name="methodName" /> is null.</exception>
773         ///<exception cref="T:System.InvalidOperationException">No method whose name is <paramref name="methodName" />, whose type parameters match <paramref name="typeArguments" />, and whose parameter types match <paramref name="arguments" /> is found in <paramref name="type" /> or its base types.-or-More than one method whose name is <paramref name="methodName" />, whose type parameters match <paramref name="typeArguments" />, and whose parameter types match <paramref name="arguments" /> is found in <paramref name="type" /> or its base types.</exception>
774         public static MethodCallExpression Call(Type type, string methodName, Type[] typeArguments, params Expression[] arguments) {
775             ContractUtils.RequiresNotNull(type, "type");
776             ContractUtils.RequiresNotNull(methodName, "methodName");
777
778             if (arguments == null) arguments = new Expression[] { };
779             BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
780             return Expression.Call(null, FindMethod(type, methodName, typeArguments, arguments, flags), arguments);
781         }
782
783         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents a method call.</summary>
784         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" />, <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" />, and <see cref="P:System.Linq.Expressions.MethodCallExpression.Arguments" /> properties set to the specified values.</returns>
785         ///<param name="instance">An <see cref="T:System.Linq.Expressions.Expression" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> property equal to (pass null for a static (Shared in Visual Basic) method).</param>
786         ///<param name="method">A <see cref="T:System.Reflection.MethodInfo" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Method" /> property equal to.</param>
787         ///<param name="arguments">An <see cref="T:System.Collections.Generic.IEnumerable`1" /> that contains <see cref="T:System.Linq.Expressions.Expression" /> objects to use to populate the <see cref="P:System.Linq.Expressions.MethodCallExpression.Arguments" /> collection.</param>
788         ///<exception cref="T:System.ArgumentNullException">
789         ///<paramref name="method" /> is null.-or-<paramref name="instance" /> is null and <paramref name="method" /> represents an instance method.</exception>
790         ///<exception cref="T:System.ArgumentException">
791         ///<paramref name="instance" />.Type is not assignable to the declaring type of the method represented by <paramref name="method" />.-or-The number of elements in <paramref name="arguments" /> does not equal the number of parameters for the method represented by <paramref name="method" />.-or-One or more of the elements of <paramref name="arguments" /> is not assignable to the corresponding parameter for the method represented by <paramref name="method" />.</exception>
792         public static MethodCallExpression Call(Expression instance, MethodInfo method, IEnumerable<Expression> arguments) {
793             ContractUtils.RequiresNotNull(method, "method");
794
795             ReadOnlyCollection<Expression> argList = arguments.ToReadOnly();
796
797             ValidateMethodInfo(method);
798             ValidateStaticOrInstanceMethod(instance, method);
799             ValidateArgumentTypes(method, ExpressionType.Call, ref argList);
800
801             if (instance == null) {
802                 return new MethodCallExpressionN(method, argList);
803             } else {
804                 return new InstanceMethodCallExpressionN(method, instance, argList);
805             }
806         }
807
808         private static ParameterInfo[] ValidateMethodAndGetParameters(Expression instance, MethodInfo method) {
809             ValidateMethodInfo(method);
810             ValidateStaticOrInstanceMethod(instance, method);
811
812             return GetParametersForValidation(method, ExpressionType.Call);
813         }
814
815         private static void ValidateStaticOrInstanceMethod(Expression instance, MethodInfo method) {
816             if (method.IsStatic) {
817                 if (instance != null) throw new ArgumentException(Strings.OnlyStaticMethodsHaveNullInstance, "instance");
818             } else {
819                 if (instance == null) throw new ArgumentException(Strings.OnlyStaticMethodsHaveNullInstance, "method");
820                 RequiresCanRead(instance, "instance");
821                 ValidateCallInstanceType(instance.Type, method);
822             }
823         }
824
825         private static void ValidateCallInstanceType(Type instanceType, MethodInfo method) {
826             if (!TypeUtils.IsValidInstanceType(method, instanceType)) {
827                 throw Error.InstanceAndMethodTypeMismatch(method, method.DeclaringType, instanceType);
828             }
829         }
830
831         private static void ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ref ReadOnlyCollection<Expression> arguments) {
832             Debug.Assert(nodeKind == ExpressionType.Invoke || nodeKind == ExpressionType.Call || nodeKind == ExpressionType.Dynamic || nodeKind == ExpressionType.New);
833
834             ParameterInfo[] pis = GetParametersForValidation(method, nodeKind);
835
836             ValidateArgumentCount(method, nodeKind, arguments.Count, pis);
837
838             Expression[] newArgs = null;
839             for (int i = 0, n = pis.Length; i < n; i++) {
840                 Expression arg = arguments[i];
841                 ParameterInfo pi = pis[i];
842                 arg = ValidateOneArgument(method, nodeKind, arg, pi);
843
844                 if (newArgs == null && arg != arguments[i]) {
845                     newArgs = new Expression[arguments.Count];
846                     for (int j = 0; j < i; j++) {
847                         newArgs[j] = arguments[j];
848                     }
849                 }
850                 if (newArgs != null) {
851                     newArgs[i] = arg;
852                 }
853             }
854             if (newArgs != null) {
855                 arguments = new TrueReadOnlyCollection<Expression>(newArgs);
856             }
857         }
858
859         private static ParameterInfo[] GetParametersForValidation(MethodBase method, ExpressionType nodeKind) {
860             ParameterInfo[] pis = method.GetParametersCached();
861
862             if (nodeKind == ExpressionType.Dynamic) {
863                 pis = pis.RemoveFirst(); // ignore CallSite argument
864             }
865             return pis;
866         }
867
868         private static void ValidateArgumentCount(MethodBase method, ExpressionType nodeKind, int count, ParameterInfo[] pis) {
869             if (pis.Length != count) {
870                 // Throw the right error for the node we were given
871                 switch (nodeKind) {
872                     case ExpressionType.New:
873                         throw Error.IncorrectNumberOfConstructorArguments();
874                     case ExpressionType.Invoke:
875                         throw Error.IncorrectNumberOfLambdaArguments();
876                     case ExpressionType.Dynamic:
877                     case ExpressionType.Call:
878                         throw Error.IncorrectNumberOfMethodCallArguments(method);
879                     default:
880                         throw ContractUtils.Unreachable;
881                 }
882             }
883         }
884
885         private static Expression ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi) {
886             RequiresCanRead(arg, "arguments");
887             Type pType = pi.ParameterType;
888             if (pType.IsByRef) {
889                 pType = pType.GetElementType();
890             }
891             TypeUtils.ValidateType(pType);
892             if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) {
893                 if (TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), pType) && pType.IsAssignableFrom(arg.GetType())) {
894                     arg = Expression.Quote(arg);
895                 } else {
896                     // Throw the right error for the node we were given
897                     switch (nodeKind) {
898                         case ExpressionType.New:
899                             throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);
900                         case ExpressionType.Invoke:
901                             throw Error.ExpressionTypeDoesNotMatchParameter(arg.Type, pType);
902                         case ExpressionType.Dynamic:
903                         case ExpressionType.Call:
904                             throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method);
905                         default:
906                             throw ContractUtils.Unreachable;
907                     }
908                 }
909             }
910             return arg;
911         }
912
913         private static MethodInfo FindMethod(Type type, string methodName, Type[] typeArgs, Expression[] args, BindingFlags flags) {
914             MemberInfo[] members = type.FindMembers(MemberTypes.Method, flags, Type.FilterNameIgnoreCase, methodName);
915             if (members == null || members.Length == 0)
916                 throw Error.MethodDoesNotExistOnType(methodName, type);
917
918             MethodInfo method;
919
920             var methodInfos = members.Map(t => (MethodInfo)t);
921             int count = FindBestMethod(methodInfos, typeArgs, args, out method);
922
923             if (count == 0) {
924                 if (typeArgs != null && typeArgs.Length > 0) {
925                     throw Error.GenericMethodWithArgsDoesNotExistOnType(methodName, type);
926                 } else {
927                     throw Error.MethodWithArgsDoesNotExistOnType(methodName, type);
928                 }
929             }
930             if (count > 1)
931                 throw Error.MethodWithMoreThanOneMatch(methodName, type);
932             return method;
933         }
934
935         private static int FindBestMethod(IEnumerable<MethodInfo> methods, Type[] typeArgs, Expression[] args, out MethodInfo method) {
936             int count = 0;
937             method = null;
938             foreach (MethodInfo mi in methods) {
939                 MethodInfo moo = ApplyTypeArgs(mi, typeArgs);
940                 if (moo != null && IsCompatible(moo, args)) {
941                     // favor public over non-public methods
942                     if (method == null || (!method.IsPublic && moo.IsPublic)) {
943                         method = moo;
944                         count = 1;
945                     }
946                         // only count it as additional method if they both public or both non-public
947                     else if (method.IsPublic == moo.IsPublic) {
948                         count++;
949                     }
950                 }
951             }
952             return count;
953         }
954
955         private static bool IsCompatible(MethodBase m, Expression[] args) {
956             ParameterInfo[] parms = m.GetParametersCached();
957             if (parms.Length != args.Length)
958                 return false;
959             for (int i = 0; i < args.Length; i++) {
960                 Expression arg = args[i];
961                 ContractUtils.RequiresNotNull(arg, "argument");
962                 Type argType = arg.Type;
963                 Type pType = parms[i].ParameterType;
964                 if (pType.IsByRef) {
965                     pType = pType.GetElementType();
966                 }
967                 if (!TypeUtils.AreReferenceAssignable(pType, argType) &&
968                     !(TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), pType) && pType.IsAssignableFrom(arg.GetType()))) {
969                     return false;
970                 }
971             }
972             return true;
973         }
974
975         private static MethodInfo ApplyTypeArgs(MethodInfo m, Type[] typeArgs) {
976             if (typeArgs == null || typeArgs.Length == 0) {
977                 if (!m.IsGenericMethodDefinition)
978                     return m;
979             } else {
980                 if (m.IsGenericMethodDefinition && m.GetGenericArguments().Length == typeArgs.Length)
981                     return m.MakeGenericMethod(typeArgs);
982             }
983             return null;
984         }
985
986
987         #endregion
988
989         #region ArrayIndex
990
991         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents applying an array index operator to a multi-dimensional array.</summary>
992         ///<returns>A <see cref="T:System.Linq.Expressions.BinaryExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.ArrayIndex" /> and the <see cref="P:System.Linq.Expressions.BinaryExpression.Left" /> and <see cref="P:System.Linq.Expressions.BinaryExpression.Right" /> properties set to the specified values.</returns>
993         ///<param name="array">An array of <see cref="T:System.Linq.Expressions.Expression" /> instances - indexes for the array index operation.</param>
994         ///<param name="indexes">An array that contains <see cref="T:System.Linq.Expressions.Expression" /> objects to use to populate the <see cref="P:System.Linq.Expressions.MethodCallExpression.Arguments" /> collection.</param>
995         public static MethodCallExpression ArrayIndex(Expression array, params Expression[] indexes) {
996             return ArrayIndex(array, (IEnumerable<Expression>)indexes);
997         }
998
999         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents applying an array index operator to an array of rank more than one.</summary>
1000         ///<returns>A <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.Call" /> and the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> and <see cref="P:System.Linq.Expressions.MethodCallExpression.Arguments" /> properties set to the specified values.</returns>
1001         ///<param name="array">An <see cref="T:System.Linq.Expressions.Expression" /> to set the <see cref="P:System.Linq.Expressions.MethodCallExpression.Object" /> property equal to.</param>
1002         ///<param name="indexes">An <see cref="T:System.Collections.Generic.IEnumerable`1" /> that contains <see cref="T:System.Linq.Expressions.Expression" /> objects to use to populate the <see cref="P:System.Linq.Expressions.MethodCallExpression.Arguments" /> collection.</param>
1003         ///<exception cref="T:System.ArgumentNullException">
1004         ///<paramref name="array" /> or <paramref name="indexes" /> is null.</exception>
1005         ///<exception cref="T:System.ArgumentException">
1006         ///<paramref name="array" />.Type does not represent an array type.-or-The rank of <paramref name="array" />.Type does not match the number of elements in <paramref name="indexes" />.-or-The <see cref="P:System.Linq.Expressions.Expression.Type" /> property of one or more elements of <paramref name="indexes" /> does not represent the <see cref="T:System.Int32" /> type.</exception>
1007         public static MethodCallExpression ArrayIndex(Expression array, IEnumerable<Expression> indexes) {
1008             RequiresCanRead(array, "array");
1009             ContractUtils.RequiresNotNull(indexes, "indexes");
1010
1011             Type arrayType = array.Type;
1012             if (!arrayType.IsArray) {
1013                 throw Error.ArgumentMustBeArray();
1014             }
1015
1016             ReadOnlyCollection<Expression> indexList = indexes.ToReadOnly();
1017             if (arrayType.GetArrayRank() != indexList.Count) {
1018                 throw Error.IncorrectNumberOfIndexes();
1019             }
1020
1021             foreach (Expression e in indexList) {
1022                 RequiresCanRead(e, "indexes");
1023                 if (e.Type != typeof(int)) {
1024                     throw Error.ArgumentMustBeArrayIndexType();
1025                 }
1026             }
1027
1028             MethodInfo mi = array.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance);
1029             return Call(array, mi, indexList);
1030         }
1031
1032         #endregion
1033
1034     }
1035 }