+ if (candidate_pd.Count == 0 && argument_count == 0)
+ return 1;
+
+ if (best == null) {
+ if (candidate_pd.Count == argument_count) {
+ int x = 0;
+ for (int j = argument_count; j > 0;) {
+ j--;
+
+ Argument a = (Argument) args [j];
+
+ x = BetterConversion (
+ ec, a, candidate_pd.ParameterType (j), null,
+ use_standard, loc);
+
+ if (x <= 0)
+ break;
+ }
+
+ if (x > 0)
+ return 1;
+ else
+ return 0;
+
+ } else
+ return 0;
+ }
+
+ best_pd = GetParameterData (best);
+
+ if (candidate_pd.Count == argument_count && best_pd.Count == argument_count) {
+ int rating1 = 0, rating2 = 0;
+
+ for (int j = argument_count; j > 0;) {
+ j--;
+ int x, y;
+
+ Argument a = (Argument) args [j];
+
+ x = BetterConversion (ec, a, candidate_pd.ParameterType (j),
+ best_pd.ParameterType (j), use_standard, loc);
+ y = BetterConversion (ec, a, best_pd.ParameterType (j),
+ candidate_pd.ParameterType (j), use_standard,
+ loc);
+
+ rating1 += x;
+ rating2 += y;
+ }
+
+ if (rating1 > rating2)
+ return 1;
+ else
+ return 0;
+ } else
+ return 0;
+
+ }
+
+ public static string FullMethodDesc (MethodBase mb)
+ {
+ StringBuilder sb = new StringBuilder (mb.Name);
+ ParameterData pd = GetParameterData (mb);
+
+ int count = pd.Count;
+ sb.Append (" (");
+
+ for (int i = count; i > 0; ) {
+ i--;
+
+ sb.Append (pd.ParameterDesc (count - i - 1));
+ if (i != 0)
+ sb.Append (", ");
+ }
+
+ sb.Append (")");
+ return sb.ToString ();
+ }
+
+ public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2)
+ {
+ MemberInfo [] miset;
+ MethodGroupExpr union;
+
+ if (mg1 != null && mg2 != null) {
+
+ MethodGroupExpr left_set = null, right_set = null;
+ int length1 = 0, length2 = 0;
+
+ left_set = (MethodGroupExpr) mg1;
+ length1 = left_set.Methods.Length;
+
+ right_set = (MethodGroupExpr) mg2;
+ length2 = right_set.Methods.Length;
+
+ ArrayList common = new ArrayList ();
+
+ for (int i = 0; i < left_set.Methods.Length; i++) {
+ for (int j = 0; j < right_set.Methods.Length; j++) {
+ if (left_set.Methods [i] == right_set.Methods [j])
+ common.Add (left_set.Methods [i]);
+ }
+ }
+
+ miset = new MemberInfo [length1 + length2 - common.Count];
+
+ left_set.Methods.CopyTo (miset, 0);
+
+ int k = 0;
+
+ for (int j = 0; j < right_set.Methods.Length; j++)
+ if (!common.Contains (right_set.Methods [j]))
+ miset [length1 + k++] = right_set.Methods [j];
+
+ union = new MethodGroupExpr (miset);
+
+ return union;
+
+ } else if (mg1 == null && mg2 != null) {
+
+ MethodGroupExpr me = (MethodGroupExpr) mg2;
+
+ miset = new MemberInfo [me.Methods.Length];
+ me.Methods.CopyTo (miset, 0);
+
+ union = new MethodGroupExpr (miset);
+
+ return union;
+
+ } else if (mg2 == null && mg1 != null) {
+
+ MethodGroupExpr me = (MethodGroupExpr) mg1;
+
+ miset = new MemberInfo [me.Methods.Length];
+ me.Methods.CopyTo (miset, 0);
+
+ union = new MethodGroupExpr (miset);
+
+ return union;
+ }
+
+ return null;
+ }
+
+ // <summary>
+ // Determines is the candidate method, if a params method, is applicable
+ // in its expanded form to the given set of arguments
+ // </summary>
+ static bool IsParamsMethodApplicable (ArrayList arguments, MethodBase candidate)
+ {
+ int arg_count;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+ ParameterData pd = GetParameterData (candidate);
+
+ int pd_count = pd.Count;
+
+ if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
+ return false;
+
+ if (pd_count - 1 > arg_count)
+ return false;
+
+ // If we have come this far, the case which remains is when the number of parameters
+ // is less than or equal to the argument count. So, we now check if the element type
+ // of the params array is compatible with each argument type
+ //
+
+ Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
+
+ for (int i = pd_count - 1; i < arg_count - 1; i++) {
+ Argument a = (Argument) arguments [i];
+ if (!StandardConversionExists (a.Type, element_type))
+ return false;
+ }
+
+ return true;
+ }
+
+ // <summary>
+ // Determines if the candidate method is applicable (section 14.4.2.1)
+ // to the given set of arguments
+ // </summary>
+ static bool IsApplicable (ArrayList arguments, MethodBase candidate)
+ {
+ int arg_count;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+ ParameterData pd = GetParameterData (candidate);
+
+ int pd_count = pd.Count;
+
+ if (arg_count != pd.Count)
+ return false;
+
+ for (int i = arg_count; i > 0; ) {
+ i--;
+
+ Argument a = (Argument) arguments [i];
+
+ Parameter.Modifier a_mod = a.GetParameterModifier ();
+ Parameter.Modifier p_mod = pd.ParameterModifier (i);
+
+ if (a_mod == p_mod) {
+
+ if (a_mod == Parameter.Modifier.NONE)
+ if (!StandardConversionExists (a.Type, pd.ParameterType (i)))
+ return false;
+
+ if (a_mod == Parameter.Modifier.REF ||
+ a_mod == Parameter.Modifier.OUT)
+ if (pd.ParameterType (i) != a.Type)
+ return false;
+ } else
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+ // <summary>
+ // Find the Applicable Function Members (7.4.2.1)
+ //
+ // me: Method Group expression with the members to select.
+ // it might contain constructors or methods (or anything
+ // that maps to a method).
+ //
+ // Arguments: ArrayList containing resolved Argument objects.
+ //
+ // loc: The location if we want an error to be reported, or a Null
+ // location for "probing" purposes.
+ //
+ // use_standard: controls whether OverloadResolve should use the
+ // ConvertImplicit or ConvertImplicitStandard during overload resolution.
+ //
+ // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
+ // that is the best match of me on Arguments.
+ //
+ // </summary>
+ public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+ ArrayList Arguments, Location loc,
+ bool use_standard)
+ {
+ ArrayList afm = new ArrayList ();
+ int best_match_idx = -1;
+ MethodBase method = null;
+ int argument_count;
+
+ for (int i = me.Methods.Length; i > 0; ){
+ i--;
+ MethodBase candidate = me.Methods [i];
+ int x;
+
+ // Check if candidate is applicable (section 14.4.2.1)
+ if (!IsApplicable (Arguments, candidate))
+ continue;
+
+ x = BetterFunction (ec, Arguments, candidate, method, use_standard, loc);
+
+ if (x == 0)
+ continue;
+ else {
+ best_match_idx = i;
+ method = me.Methods [best_match_idx];
+ }
+ }
+
+ if (Arguments == null)
+ argument_count = 0;
+ else
+ argument_count = Arguments.Count;
+
+ //
+ // Now we see if we can find params functions, applicable in their expanded form
+ // since if they were applicable in their normal form, they would have been selected
+ // above anyways
+ //
+ if (best_match_idx == -1) {
+
+ for (int i = me.Methods.Length; i > 0; ) {
+ i--;
+ MethodBase candidate = me.Methods [i];
+
+ if (IsParamsMethodApplicable (Arguments, candidate)) {
+ best_match_idx = i;
+ method = me.Methods [best_match_idx];
+ break;
+ }
+ }
+ }
+
+ //
+ // Now we see if we can at least find a method with the same number of arguments
+ //
+ ParameterData pd;
+
+ if (best_match_idx == -1) {
+
+ for (int i = me.Methods.Length; i > 0;) {
+ i--;
+ MethodBase mb = me.Methods [i];
+ pd = GetParameterData (mb);
+
+ if (pd.Count == argument_count) {
+ best_match_idx = i;
+ method = me.Methods [best_match_idx];
+ break;
+ } else
+ continue;
+ }
+ }
+
+ if (method == null)
+ return null;
+
+ // And now convert implicitly, each argument to the required type
+
+ pd = GetParameterData (method);
+ int pd_count = pd.Count;
+
+ for (int j = 0; j < argument_count; j++) {
+
+ Argument a = (Argument) Arguments [j];
+ Expression a_expr = a.Expr;
+ Type parameter_type = pd.ParameterType (j);
+
+ //
+ // Note that we need to compare against the element type
+ // when we have a params method
+ //
+ if (pd.ParameterModifier (pd_count - 1) == Parameter.Modifier.PARAMS) {
+ if (j >= pd_count - 1)
+ parameter_type = pd.ParameterType (pd_count - 1).GetElementType ();
+ }
+
+ if (a.Type != parameter_type){
+ Expression conv;
+
+ if (use_standard)
+ conv = ConvertImplicitStandard (ec, a_expr, parameter_type, Location.Null);
+ else
+ conv = ConvertImplicit (ec, a_expr, parameter_type, Location.Null);
+
+ if (conv == null) {
+ if (!Location.IsNull (loc)) {
+ Error (1502, loc,
+ "The best overloaded match for method '" + FullMethodDesc (method)+
+ "' has some invalid arguments");
+ Error (1503, loc,
+ "Argument " + (j+1) +
+ ": Cannot convert from '" + Argument.FullDesc (a)
+ + "' to '" + pd.ParameterDesc (j) + "'");
+ }
+ return null;
+ }
+
+
+
+ //
+ // Update the argument with the implicit conversion
+ //
+ if (a_expr != conv)
+ a.Expr = conv;
+
+ // FIXME : For the case of params methods, we need to actually instantiate
+ // an array and initialize it with the argument values etc etc.
+
+ }
+
+ if (a.GetParameterModifier () != pd.ParameterModifier (j) &&
+ pd.ParameterModifier (j) != Parameter.Modifier.PARAMS) {
+ if (!Location.IsNull (loc)) {
+ Error (1502, loc,
+ "The best overloaded match for method '" + FullMethodDesc (method)+
+ "' has some invalid arguments");
+ Error (1503, loc,
+ "Argument " + (j+1) +
+ ": Cannot convert from '" + Argument.FullDesc (a)
+ + "' to '" + pd.ParameterDesc (j) + "'");
+ }
+ return null;
+ }
+
+
+ }
+
+ return method;
+ }
+
+ public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+ ArrayList Arguments, Location loc)
+ {
+ return OverloadResolve (ec, me, Arguments, loc, false);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // First, resolve the expression that is used to
+ // trigger the invocation
+ //
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return null;
+
+ if (!(expr is MethodGroupExpr)) {
+ Type expr_type = expr.Type;
+
+ if (expr_type != null){
+ bool IsDelegate = TypeManager.IsDelegateType (expr_type);
+ if (IsDelegate)
+ return (new DelegateInvocation (
+ this.expr, Arguments, loc)).Resolve (ec);
+ }
+ }
+
+ if (!(expr is MethodGroupExpr)){
+ report118 (loc, this.expr, "method group");
+ return null;
+ }
+
+ //
+ // Next, evaluate all the expressions in the argument list
+ //
+ if (Arguments != null){
+ for (int i = Arguments.Count; i > 0;){
+ --i;
+ Argument a = (Argument) Arguments [i];
+
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc);
+
+ if (method == null){
+ Error (-6, loc,
+ "Could not find any applicable function for this argument list");
+ return null;
+ }
+
+ if (method is MethodInfo)
+ type = ((MethodInfo)method).ReturnType;
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ // <summary>
+ // Emits the list of arguments as an array
+ // </summary>
+ static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
+ {
+ ILGenerator ig = ec.ig;
+ int count = arguments.Count - idx;
+ Argument a = (Argument) arguments [idx];
+ Type t = a.expr.Type;
+ string array_type = t.FullName + "[]";
+ LocalBuilder array;
+
+ array = ig.DeclareLocal (Type.GetType (array_type));
+ IntLiteral.EmitInt (ig, count);
+ ig.Emit (OpCodes.Newarr, t);
+ ig.Emit (OpCodes.Stloc, array);
+
+ int top = arguments.Count;
+ for (int j = idx; j < top; j++){
+ a = (Argument) arguments [j];
+
+ ig.Emit (OpCodes.Ldloc, array);
+ IntLiteral.EmitInt (ig, j - idx);
+ a.Emit (ec);
+
+ ArrayAccess.EmitStoreOpcode (ig, t);
+ }
+ ig.Emit (OpCodes.Ldloc, array);
+ }
+
+ // <summary>
+ // Emits a list of resolved Arguments that are in the arguments
+ // ArrayList.
+ //
+ // The MethodBase argument might be null if the
+ // emission of the arguments is known not to contain
+ // a `params' field (for example in constructors or other routines
+ // that keep their arguments in this structure
+ // </summary>
+
+ public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
+ {
+ ParameterData pd = null;
+ int top;
+
+ if (arguments != null)
+ top = arguments.Count;
+ else
+ top = 0;
+
+ if (mb != null)
+ pd = GetParameterData (mb);
+
+ for (int i = 0; i < top; i++){
+ Argument a = (Argument) arguments [i];
+
+ if (pd != null){
+ if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
+ EmitParams (ec, i, arguments);
+ return;
+ }
+ }
+
+ a.Emit (ec);
+ }
+ }
+
+ public static void EmitCall (EmitContext ec,
+ bool is_static, Expression instance_expr,
+ MethodBase method, ArrayList Arguments)
+ {
+ ILGenerator ig = ec.ig;
+ bool struct_call = false;
+
+ if (!is_static){
+ //
+ // If this is ourselves, push "this"
+ //
+ if (instance_expr == null){
+ ig.Emit (OpCodes.Ldarg_0);
+ } else {
+ //
+ // Push the instance expression
+ //
+ if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
+
+ struct_call = true;
+
+ //
+ // If the expression implements IMemoryLocation, then
+ // we can optimize and use AddressOf on the
+ // return.
+ //
+ // If not we have to use some temporary storage for
+ // it.
+ if (instance_expr is IMemoryLocation)
+ ((IMemoryLocation) instance_expr).AddressOf (ec);
+ else {
+ Type t = instance_expr.Type;
+
+ instance_expr.Emit (ec);
+ LocalBuilder temp = ig.DeclareLocal (t);
+ ig.Emit (OpCodes.Stloc, temp);
+ ig.Emit (OpCodes.Ldloca, temp);
+ }
+ } else
+ instance_expr.Emit (ec);
+ }
+ }
+
+ if (Arguments != null)
+ EmitArguments (ec, method, Arguments);
+
+ if (is_static || struct_call){
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ } else {
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ MethodGroupExpr mg = (MethodGroupExpr) this.expr;
+ EmitCall (ec, method.IsStatic, mg.InstanceExpression, method, Arguments);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+
+ //
+ // Pop the return value if there is one
+ //
+ if (method is MethodInfo){
+ if (((MethodInfo)method).ReturnType != TypeManager.void_type)
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+ }
+
+ public class New : ExpressionStatement {
+ public readonly ArrayList Arguments;
+ public readonly string RequestedType;
+
+ Location loc;
+ MethodBase method = null;
+
+ //
+ // If set, the new expression is for a value_target, and
+ // we will not leave anything on the stack.
+ //
+ Expression value_target;
+
+ public New (string requested_type, ArrayList arguments, Location l)
+ {
+ RequestedType = requested_type;
+ Arguments = arguments;
+ loc = l;
+ }
+
+ public Expression ValueTypeVariable {
+ get {
+ return value_target;
+ }
+
+ set {
+ value_target = value;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = ec.TypeContainer.LookupType (RequestedType, false);
+
+ if (type == null)
+ return null;
+
+ bool IsDelegate = TypeManager.IsDelegateType (type);
+
+ if (IsDelegate)
+ return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+
+ Expression ml;
+
+ ml = MemberLookup (ec, type, ".ctor", false,
+ MemberTypes.Constructor, AllBindingsFlags, loc);
+
+ bool is_struct = false;
+ is_struct = type.IsSubclassOf (TypeManager.value_type);
+
+ if (! (ml is MethodGroupExpr)){
+ if (!is_struct){
+ report118 (loc, ml, "method group");
+ return null;
+ }
+ }
+
+ if (ml != null) {
+ if (Arguments != null){
+ for (int i = Arguments.Count; i > 0;){
+ --i;
+ Argument a = (Argument) Arguments [i];
+
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
+ Arguments, loc);
+ }
+
+ if (method == null && !is_struct) {
+ Error (-6, loc,
+ "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ //
+ // This DoEmit can be invoked in two contexts:
+ // * As a mechanism that will leave a value on the stack (new object)
+ // * As one that wont (init struct)
+ //
+ // You can control whether a value is required on the stack by passing
+ // need_value_on_stack. The code *might* leave a value on the stack
+ // so it must be popped manually
+ //
+ // Returns whether a value is left on the stack
+ //
+ bool DoEmit (EmitContext ec, bool need_value_on_stack)
+ {
+ if (method == null){
+ IMemoryLocation ml = (IMemoryLocation) value_target;
+
+ ml.AddressOf (ec);
+ } else {
+ Invocation.EmitArguments (ec, method, Arguments);
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
+ return true;
+ }
+
+ //
+ // It must be a value type, sanity check
+ //
+ if (value_target != null){
+ ec.ig.Emit (OpCodes.Initobj, type);
+
+ if (need_value_on_stack){
+ value_target.Emit (ec);
+ return true;
+ }
+ return false;
+ }
+
+ throw new Exception ("No method and no value type");
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ DoEmit (ec, true);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ if (DoEmit (ec, false))
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ // <summary>
+ // Represents an array creation expression.
+ // </summary>
+ //
+ // <remarks>
+ // There are two possible scenarios here: one is an array creation
+ // expression that specifies the dimensions and optionally the
+ // initialization data
+ // </remarks>
+ public class ArrayCreation : ExpressionStatement {
+
+ string RequestedType;
+ string Rank;
+ ArrayList Initializers;
+ Location loc;
+ ArrayList Arguments;
+
+ MethodBase method = null;
+ Type array_element_type;
+ bool IsOneDimensional = false;
+
+ bool IsBuiltinType = false;
+
+ int dimensions = 0;
+
+ public ArrayCreation (string requested_type, ArrayList exprs,
+ string rank, ArrayList initializers, Location l)
+ {
+ RequestedType = requested_type;
+ Rank = rank;
+ Initializers = initializers;
+ loc = l;