+ }
+
+ ///
+ /// 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 (EmitContext ec,
+ ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
+ {
+ MethodBase candidate = method;
+
+ ParameterData pd = TypeManager.GetParameterData (candidate);
+ int param_count = GetApplicableParametersCount (candidate, pd);
+
+ if (arg_count != param_count) {
+ if (!pd.HasParams)
+ return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
+ if (arg_count < param_count - 1)
+ return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
+ }
+
+#if GMCS_SOURCE
+ //
+ // 1. Handle generic method using type arguments when specified or type inference
+ //
+ if (TypeManager.IsGenericMethod (candidate)) {
+ if (type_arguments != null) {
+ Type [] g_args = candidate.GetGenericArguments ();
+ if (g_args.Length != type_arguments.Count)
+ return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
+
+ // TODO: Don't create new method, create Parameters only
+ method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
+ candidate = method;
+ pd = TypeManager.GetParameterData (candidate);
+ } else {
+ int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
+ if (score != 0)
+ return score - 20000;
+
+ if (TypeManager.IsGenericMethodDefinition (candidate))
+ throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
+ TypeManager.CSharpSignature (candidate));
+
+ pd = TypeManager.GetParameterData (candidate);
+ }
+ } else {
+ if (type_arguments != null)
+ return int.MaxValue - 15000;
+ }
+#endif
+
+ //
+ // 2. Each argument has to be implicitly convertible to method parameter
+ //
+ method = candidate;
+ Parameter.Modifier p_mod = 0;
+ Type pt = null;
+ for (int i = 0; i < arg_count; i++) {
+ Argument a = (Argument) arguments [i];
+ Parameter.Modifier a_mod = a.Modifier &
+ ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
+
+ if (p_mod != Parameter.Modifier.PARAMS) {
+ p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
+
+ if (p_mod == Parameter.Modifier.ARGLIST) {
+ if (a.Type == TypeManager.runtime_argument_handle_type)
+ continue;
+
+ p_mod = 0;
+ }
+
+ pt = pd.ParameterType (i);
+ } else {
+ params_expanded_form = true;
+ }
+
+ 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) {
+ // It can be applicable in expanded form
+ score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
+ 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;
+ }
+
+ int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
+ {
+ //
+ // Types have to be identical when ref or out modifer is used
+ //
+ if (arg_mod != 0 || param_mod != 0) {
+ if (TypeManager.HasElementType (parameter))
+ parameter = parameter.GetElementType ();
+
+ Type a_type = argument.Type;
+ if (TypeManager.HasElementType (a_type))
+ a_type = a_type.GetElementType ();
+
+ if (a_type != parameter)
+ return 2;
+
+ return 0;
+ }
+
+ // FIXME: Kill this abomination (EmitContext.TempEc)
+ EmitContext prevec = EmitContext.TempEc;
+ EmitContext.TempEc = ec;
+ try {
+ if (delegate_type != null ?
+ !Delegate.IsTypeCovariant (argument.Expr, parameter) :
+ !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
+ return 2;
+
+ if (arg_mod != param_mod)
+ return 1;
+
+ } finally {
+ EmitContext.TempEc = prevec;
+ }
+
+ return 0;
+ }