/// /// Determines if the candidate method is applicable (section 14.4.2.1) /// to the given set of arguments /// A return value rates candidate method compatibility, /// 0 = the best, int.MaxValue = the worst /// public int IsApplicable(ResolveContext ec, ref Arguments arguments, int arg_count, ref MethodSpec method, ref bool params_expanded_form) { var candidate = method; AParametersCollection pd = candidate.Parameters; int param_count = GetApplicableParametersCount (candidate, pd); int optional_count = 0; if (arg_count != param_count) { for (int i = 0; i < pd.Count; ++i) { if (pd.FixedParameters [i].HasDefaultValue) { optional_count = pd.Count - i; break; } } int args_gap = System.Math.Abs (arg_count - param_count); if (optional_count != 0) { if (args_gap > optional_count) return int.MaxValue - 10000 + args_gap - optional_count; // Readjust expected number when params used if (pd.HasParams) { optional_count--; if (arg_count < param_count) param_count--; } else if (arg_count > param_count) { return int.MaxValue - 10000 + args_gap; } } else if (arg_count != param_count) { if (!pd.HasParams) return int.MaxValue - 10000 + args_gap; if (arg_count < param_count - 1) return int.MaxValue - 10000 + args_gap; } // Initialize expanded form of a method with 1 params parameter params_expanded_form = param_count == 1 && pd.HasParams; // Resize to fit optional arguments if (optional_count != 0) { Arguments resized; if (arguments == null) { resized = new Arguments (optional_count); } else { resized = new Arguments (param_count); resized.AddRange (arguments); } for (int i = arg_count; i < param_count; ++i) resized.Add (null); arguments = resized; } } if (arg_count > 0) { // // Shuffle named arguments to the right positions if there are any // if (arguments [arg_count - 1] is NamedArgument) { arg_count = arguments.Count; for (int i = 0; i < arg_count; ++i) { bool arg_moved = false; while (true) { NamedArgument na = arguments[i] as NamedArgument; if (na == null) break; int index = pd.GetParameterIndexByName (na.Name); // Named parameter not found or already reordered if (index <= i) break; // When using parameters which should not be available to the user if (index >= param_count) break; if (!arg_moved) { arguments.MarkReorderedArgument (na); arg_moved = true; } Argument temp = arguments[index]; arguments[index] = arguments[i]; arguments[i] = temp; if (temp == null) break; } } } else { arg_count = arguments.Count; } } else if (arguments != null) { arg_count = arguments.Count; } // // 1. Handle generic method using type arguments when specified or type inference // if (candidate.IsGeneric) { if (type_arguments != null) { var g_args_count = candidate.Arity; if (g_args_count != type_arguments.Count) return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count); method = candidate.MakeGenericMethod (type_arguments.Arguments); candidate = method; pd = candidate.Parameters; } else { int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate); if (score != 0) return score - 20000; pd = candidate.Parameters; } } else { if (type_arguments != null) return int.MaxValue - 15000; } // // 2. Each argument has to be implicitly convertible to method parameter // method = candidate; Parameter.Modifier p_mod = 0; TypeSpec pt = null; for (int i = 0; i < arg_count; i++) { Argument a = arguments [i]; if (a == null) { if (!pd.FixedParameters [i].HasDefaultValue) throw new InternalErrorException (); Expression e = pd.FixedParameters [i].DefaultValue as Constant; if (e == null) e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec); arguments [i] = new Argument (e, Argument.AType.Default); continue; } if (p_mod != Parameter.Modifier.PARAMS) { p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK); pt = pd.Types [i]; } else { params_expanded_form = true; } Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK); int score = 1; if (!params_expanded_form) score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt); if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) { // It can be applicable in expanded form score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt)); if (score == 0) params_expanded_form = true; } if (score != 0) { if (params_expanded_form) ++score; return (arg_count - i) * 2 + score; } } if (arg_count != param_count) params_expanded_form = true; return 0; }