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