66b3bb001dc6832cb4be99567ab372f5ed4a1774
[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 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 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 SILVERLIGHT
818                 if (SilverlightQuirks) return;
819 #endif
820                 if (instance != null) throw new ArgumentException(Strings.OnlyStaticMethodsHaveNullInstance, "instance");
821             } else {
822                 if (instance == null) throw new ArgumentException(Strings.OnlyStaticMethodsHaveNullInstance, "method");
823                 RequiresCanRead(instance, "instance");
824                 ValidateCallInstanceType(instance.Type, method);
825             }
826         }
827
828         private static void ValidateCallInstanceType(Type instanceType, MethodInfo method) {
829             if (!TypeUtils.IsValidInstanceType(method, instanceType)) {
830                 throw Error.InstanceAndMethodTypeMismatch(method, method.DeclaringType, instanceType);
831             }
832         }
833
834         private static void ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ref ReadOnlyCollection<Expression> arguments) {
835             Debug.Assert(nodeKind == ExpressionType.Invoke || nodeKind == ExpressionType.Call || nodeKind == ExpressionType.Dynamic || nodeKind == ExpressionType.New);
836
837             ParameterInfo[] pis = GetParametersForValidation(method, nodeKind);
838
839             ValidateArgumentCount(method, nodeKind, arguments.Count, pis);
840
841             Expression[] newArgs = null;
842             for (int i = 0, n = pis.Length; i < n; i++) {
843                 Expression arg = arguments[i];
844                 ParameterInfo pi = pis[i];
845                 arg = ValidateOneArgument(method, nodeKind, arg, pi);
846
847                 if (newArgs == null && arg != arguments[i]) {
848                     newArgs = new Expression[arguments.Count];
849                     for (int j = 0; j < i; j++) {
850                         newArgs[j] = arguments[j];
851                     }
852                 }
853                 if (newArgs != null) {
854                     newArgs[i] = arg;
855                 }
856             }
857             if (newArgs != null) {
858                 arguments = new TrueReadOnlyCollection<Expression>(newArgs);
859             }
860         }
861
862         private static ParameterInfo[] GetParametersForValidation(MethodBase method, ExpressionType nodeKind) {
863             ParameterInfo[] pis = method.GetParametersCached();
864
865             if (nodeKind == ExpressionType.Dynamic) {
866                 pis = pis.RemoveFirst(); // ignore CallSite argument
867             }
868             return pis;
869         }
870
871         private static void ValidateArgumentCount(MethodBase method, ExpressionType nodeKind, int count, ParameterInfo[] pis) {
872             if (pis.Length != count) {
873                 // Throw the right error for the node we were given
874                 switch (nodeKind) {
875                     case ExpressionType.New:
876                         throw Error.IncorrectNumberOfConstructorArguments();
877                     case ExpressionType.Invoke:
878                         throw Error.IncorrectNumberOfLambdaArguments();
879                     case ExpressionType.Dynamic:
880                     case ExpressionType.Call:
881                         throw Error.IncorrectNumberOfMethodCallArguments(method);
882                     default:
883                         throw ContractUtils.Unreachable;
884                 }
885             }
886         }
887
888         private static Expression ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi) {
889             RequiresCanRead(arg, "arguments");
890             Type pType = pi.ParameterType;
891             if (pType.IsByRef) {
892                 pType = pType.GetElementType();
893             }
894             TypeUtils.ValidateType(pType);
895             if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) {
896                 if (!TryQuote(pType, ref arg)) {
897                     // Throw the right error for the node we were given
898                     switch (nodeKind) {
899                         case ExpressionType.New:
900                             throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);
901                         case ExpressionType.Invoke:
902                             throw Error.ExpressionTypeDoesNotMatchParameter(arg.Type, pType);
903                         case ExpressionType.Dynamic:
904                         case ExpressionType.Call:
905                             throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method);
906                         default:
907                             throw ContractUtils.Unreachable;
908                     }
909                 }
910             }
911             return arg;
912         }
913
914         // Attempts to auto-quote the expression tree. Returns true if it succeeded, false otherwise.
915         private static bool TryQuote(Type parameterType, ref Expression argument) {
916             // We used to allow quoting of any expression, but the behavior of
917             // quote (produce a new tree closed over parameter values), only
918             // works consistently for lambdas
919             Type quoteable = typeof(LambdaExpression);
920 #if SILVERLIGHT
921             if (SilverlightQuirks) quoteable = typeof(Expression);
922 #endif
923             if (TypeUtils.IsSameOrSubclass(quoteable, parameterType) &&
924                 parameterType.IsAssignableFrom(argument.GetType())) {
925                 argument = Expression.Quote(argument);
926                 return true;
927             }
928             return false;
929         }
930
931         private static MethodInfo FindMethod(Type type, string methodName, Type[] typeArgs, Expression[] args, BindingFlags flags) {
932             MemberInfo[] members = type.FindMembers(MemberTypes.Method, flags, Type.FilterNameIgnoreCase, methodName);
933             if (members == null || members.Length == 0)
934                 throw Error.MethodDoesNotExistOnType(methodName, type);
935
936             MethodInfo method;
937
938             var methodInfos = members.Map(t => (MethodInfo)t);
939             int count = FindBestMethod(methodInfos, typeArgs, args, out method);
940
941             if (count == 0) {
942                 if (typeArgs != null && typeArgs.Length > 0) {
943                     throw Error.GenericMethodWithArgsDoesNotExistOnType(methodName, type);
944                 } else {
945                     throw Error.MethodWithArgsDoesNotExistOnType(methodName, type);
946                 }
947             }
948             if (count > 1)
949                 throw Error.MethodWithMoreThanOneMatch(methodName, type);
950             return method;
951         }
952
953         private static int FindBestMethod(IEnumerable<MethodInfo> methods, Type[] typeArgs, Expression[] args, out MethodInfo method) {
954             int count = 0;
955             method = null;
956             foreach (MethodInfo mi in methods) {
957                 MethodInfo moo = ApplyTypeArgs(mi, typeArgs);
958                 if (moo != null && IsCompatible(moo, args)) {
959                     // favor public over non-public methods
960                     if (method == null || (!method.IsPublic && moo.IsPublic)) {
961                         method = moo;
962                         count = 1;
963                     }
964                         // only count it as additional method if they both public or both non-public
965                     else if (method.IsPublic == moo.IsPublic) {
966                         count++;
967                     }
968                 }
969             }
970             return count;
971         }
972
973         private static bool IsCompatible(MethodBase m, Expression[] args) {
974             ParameterInfo[] parms = m.GetParametersCached();
975             if (parms.Length != args.Length)
976                 return false;
977             for (int i = 0; i < args.Length; i++) {
978                 Expression arg = args[i];
979                 ContractUtils.RequiresNotNull(arg, "argument");
980                 Type argType = arg.Type;
981                 Type pType = parms[i].ParameterType;
982                 if (pType.IsByRef) {
983                     pType = pType.GetElementType();
984                 }
985                 if (!TypeUtils.AreReferenceAssignable(pType, argType) &&
986                     !(TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), pType) && pType.IsAssignableFrom(arg.GetType()))) {
987                     return false;
988                 }
989             }
990             return true;
991         }
992
993         private static MethodInfo ApplyTypeArgs(MethodInfo m, Type[] typeArgs) {
994             if (typeArgs == null || typeArgs.Length == 0) {
995                 if (!m.IsGenericMethodDefinition)
996                     return m;
997             } else {
998                 if (m.IsGenericMethodDefinition && m.GetGenericArguments().Length == typeArgs.Length)
999                     return m.MakeGenericMethod(typeArgs);
1000             }
1001             return null;
1002         }
1003
1004
1005         #endregion
1006
1007         #region ArrayIndex
1008
1009         ///<summary>Creates a <see cref="T:System.Linq.Expressions.MethodCallExpression" /> that represents applying an array index operator to a multi-dimensional array.</summary>
1010         ///<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>
1011         ///<param name="array">An array of <see cref="T:System.Linq.Expressions.Expression" /> instances - indexes for the array index operation.</param>
1012         ///<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>
1013         public static MethodCallExpression ArrayIndex(Expression array, params Expression[] indexes) {
1014             return ArrayIndex(array, (IEnumerable<Expression>)indexes);
1015         }
1016
1017         ///<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>
1018         ///<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>
1019         ///<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>
1020         ///<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>
1021         ///<exception cref="T:System.ArgumentNullException">
1022         ///<paramref name="array" /> or <paramref name="indexes" /> is null.</exception>
1023         ///<exception cref="T:System.ArgumentException">
1024         ///<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>
1025         public static MethodCallExpression ArrayIndex(Expression array, IEnumerable<Expression> indexes) {
1026             RequiresCanRead(array, "array");
1027             ContractUtils.RequiresNotNull(indexes, "indexes");
1028
1029             Type arrayType = array.Type;
1030             if (!arrayType.IsArray) {
1031                 throw Error.ArgumentMustBeArray();
1032             }
1033
1034             ReadOnlyCollection<Expression> indexList = indexes.ToReadOnly();
1035             if (arrayType.GetArrayRank() != indexList.Count) {
1036                 throw Error.IncorrectNumberOfIndexes();
1037             }
1038
1039             foreach (Expression e in indexList) {
1040                 RequiresCanRead(e, "indexes");
1041                 if (e.Type != typeof(int)) {
1042                     throw Error.ArgumentMustBeArrayIndexType();
1043                 }
1044             }
1045
1046             MethodInfo mi = array.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance);
1047             return Call(array, mi, indexList);
1048         }
1049
1050         #endregion
1051
1052     }
1053 }