private static int SelectBest(TypeReferences typeRefs, MemberInfo[] match, int matches, IReflect[] argIRs, ParameterInfo[][] fparams, object[][] aparams, int candidates, int parameters) { if (candidates == 0) { return -1; } if (candidates == 1) { for (int m = 0; m < matches; m++) { if (fparams[m] != null) { return m; } } } bool[] flagArray = new bool[matches]; int[] numArray = new int[matches]; for (int i = 0; i < matches; i++) { ParameterInfo[] infoArray = fparams[i]; if (infoArray != null) { int length = infoArray.Length; int num4 = (argIRs == null) ? aparams[i].Length : argIRs.Length; if ((num4 > length) && ((length == 0) || !Microsoft.JScript.CustomAttribute.IsDefined(infoArray[length - 1], typeof(ParamArrayAttribute), false))) { fparams[i] = null; candidates--; } else { for (int n = parameters; n < length; n++) { ParameterInfo target = infoArray[n]; if ((n == (length - 1)) && Microsoft.JScript.CustomAttribute.IsDefined(target, typeof(ParamArrayAttribute), false)) { break; } if (TypeReferences.GetDefaultParameterValue(target) is DBNull) { numArray[i] = 50; } } } } } for (int j = 0; candidates > 1; j++) { int num7 = 0; int num8 = 0x7fffffff; bool flag = false; for (int num9 = 0; num9 < matches; num9++) { int num10 = 0; ParameterInfo[] infoArray2 = fparams[num9]; if (infoArray2 != null) { IReflect missing = typeRefs.Missing; if (argIRs == null) { if (aparams[num9].Length > j) { object obj3 = aparams[num9][j]; if (obj3 == null) { obj3 = DBNull.Value; } missing = typeRefs.ToReferenceContext(obj3.GetType()); } } else if (j < parameters) { missing = argIRs[j]; } int num11 = infoArray2.Length; if ((num11 - 1) > j) { num7++; } IReflect formal = typeRefs.Missing; if ((((num11 > 0) && (j >= (num11 - 1))) && (Microsoft.JScript.CustomAttribute.IsDefined(infoArray2[num11 - 1], typeof(ParamArrayAttribute), false) && !(missing is TypedArray))) && ((missing != typeRefs.ArrayObject) && (!(missing is Type) || !((Type) missing).IsArray))) { ParameterInfo info2 = infoArray2[num11 - 1]; if (info2 is ParameterDeclaration) { formal = ((TypedArray) ((ParameterDeclaration) info2).ParameterIReflect).elementType; } else { formal = info2.ParameterType.GetElementType(); } if (j == (num11 - 1)) { numArray[num9]++; } } else if (j < num11) { ParameterInfo parameter = infoArray2[j]; formal = (parameter is ParameterDeclaration) ? ((ParameterDeclaration) parameter).ParameterIReflect : parameter.ParameterType; if ((missing == typeRefs.Missing) && !(TypeReferences.GetDefaultParameterValue(parameter) is DBNull)) { missing = formal; num10 = 1; } } int num12 = (TypeDistance(typeRefs, formal, missing) + numArray[num9]) + num10; if (num12 == num8) { if ((j == (num11 - 1)) && flagArray[num9]) { candidates--; fparams[num9] = null; } flag = flag && flagArray[num9]; } else if (num12 > num8) { if ((flag && (j < num11)) && FormalParamTypeIsObject(fparams[num9][j])) { num8 = num12; } else if (((j <= (num11 - 1)) || (missing != typeRefs.Missing)) || !Microsoft.JScript.CustomAttribute.IsDefined(infoArray2[num11 - 1], typeof(ParamArrayAttribute), false)) { flagArray[num9] = true; } } else { if ((candidates == 1) && !flagArray[num9]) { return num9; } flag = flagArray[num9]; for (int num13 = 0; num13 < num9; num13++) { if ((fparams[num13] != null) && !flagArray[num13]) { bool flag2 = fparams[num13].Length <= j; if ((!flag2 || (parameters > j)) && ((flag2 || !flag) || !FormalParamTypeIsObject(fparams[num13][j]))) { flagArray[num13] = true; } } } num8 = num12; } } } if ((j >= (parameters - 1)) && (num7 < 1)) { break; } } int index = -1; for (int k = 0; (k < matches) && (candidates > 0); k++) { ParameterInfo[] suppars = fparams[k]; if (suppars != null) { if (flagArray[k]) { candidates--; fparams[k] = null; } else if (index == -1) { index = k; } else if (Class.ParametersMatch(suppars, fparams[index])) { MemberInfo info4 = match[index]; JSWrappedMethod method = match[index] as JSWrappedMethod; if (method != null) { info4 = method.method; } if (((info4 is JSFieldMethod) || (info4 is JSConstructor)) || (info4 is JSProperty)) { candidates--; fparams[k] = null; } else { Type declaringType = match[index].DeclaringType; Type c = match[k].DeclaringType; if (declaringType != c) { if (c.IsAssignableFrom(declaringType)) { candidates--; fparams[k] = null; } else if (declaringType.IsAssignableFrom(c)) { fparams[index] = null; index = k; candidates--; } } } } } } if (candidates != 1) { throw new AmbiguousMatchException(); } return index; }
internal static Type ToType(TypeReferences typeRefs, IReflect ir){ if (ir is Type) return (Type)ir; if (ir is ClassScope) return ((ClassScope)ir).GetTypeBuilderOrEnumBuilder(); if (ir is TypedArray){ return typeRefs.ToReferenceContext(((TypedArray)ir).ToType()); } if (ir is ScriptFunction) return typeRefs.ScriptFunction; return typeRefs.ToReferenceContext(ir.GetType()); }
private static int SelectBest(TypeReferences typeRefs, MemberInfo[] match, int matches, IReflect[] argIRs, ParameterInfo[][] fparams, Object[][] aparams, int candidates, int parameters){ Debug.Assert(matches > 1); if (candidates == 0) return -1; if (candidates == 1) for (int i = 0; i < matches; i++) if (fparams[i] != null) return i; bool[] eliminated = new bool[matches]; //Set up penalties to discourage selection of methods that have more formal parameters than there are actual parameters int[] penalty = new int[matches]; for (int i = 0; i < matches; i++){ ParameterInfo[] fpars = fparams[i]; if (fpars != null){ int m = fpars.Length; int actuals = (argIRs == null ? aparams[i].Length : argIRs.Length); if (actuals > m && (m == 0 || !CustomAttribute.IsDefined(fpars[m-1], typeof(ParamArrayAttribute), false))){ fparams[i] = null; candidates--; Debug.Assert(candidates >= 0); continue; } for (int j = parameters; j < m; j++){ ParameterInfo fpar = fpars[j]; if (j == m-1 && CustomAttribute.IsDefined(fpar, typeof(ParamArrayAttribute), false)) break; Object dv = TypeReferences.GetDefaultParameterValue(fpar); if (dv is System.DBNull){ //No default value, set up a penalty penalty[i] = 50; } } } } for (int p = 0; candidates > 1; p++){ int candidatesWithFormalParametersStillToBeConsidered = 0; //Eliminate any candidate that is worse match than any other candidate for this (possibly missing) actual parameter int minval = Int32.MaxValue; bool objectCanWin = false; for (int i = 0; i < matches; i++){ int penaltyForUsingDefaultValue = 0; ParameterInfo[] fpars = fparams[i]; if (fpars != null){ //match[i] is a candidate IReflect aIR = typeRefs.Missing; if (argIRs == null){ if (aparams[i].Length > p){ Object apar = aparams[i][p]; if (apar == null) apar = DBNull.Value; aIR = typeRefs.ToReferenceContext(apar.GetType()); } }else if (p < parameters) aIR = argIRs[p]; int m = fpars.Length; if (m-1 > p) candidatesWithFormalParametersStillToBeConsidered++; IReflect fIR = typeRefs.Missing; if (m > 0 && p >= m-1 && CustomAttribute.IsDefined(fpars[m-1], typeof(ParamArrayAttribute), false) && !(aIR is TypedArray || aIR == typeRefs.ArrayObject || (aIR is Type && ((Type)aIR).IsArray))){ ParameterInfo fpar = fpars[m-1]; if (fpar is ParameterDeclaration){ fIR = ((ParameterDeclaration)fpar).ParameterIReflect; fIR = ((TypedArray)fIR).elementType; }else fIR = fpar.ParameterType.GetElementType(); if (p == m-1) penalty[i]++; }else if (p < m){ ParameterInfo fpar = fpars[p]; fIR = fpar is ParameterDeclaration ? ((ParameterDeclaration)fpar).ParameterIReflect : fpar.ParameterType; if (aIR == typeRefs.Missing){ //No actual parameter was supplied, if the formal parameter has default value, make the match perfect Object dv = TypeReferences.GetDefaultParameterValue(fpar); if (!(dv is System.DBNull)) { aIR = fIR; penaltyForUsingDefaultValue = 1; } } } int distance = TypeDistance(typeRefs, fIR, aIR) + penalty[i] + penaltyForUsingDefaultValue; if (distance == minval){ if (p == m-1 && eliminated[i]){ candidates--; fparams[i] = null; } objectCanWin = objectCanWin && eliminated[i]; continue; } if (distance > minval){ if (objectCanWin && p < m && JSBinder.FormalParamTypeIsObject(fparams[i][p])){ minval = distance; //Make sure that a future, better match than Object can win. continue; } if (p > m-1 && aIR == typeRefs.Missing && CustomAttribute.IsDefined(fpars[m-1], typeof(ParamArrayAttribute), false)) continue; eliminated[i] = true; continue; } //If we get here, we have a match that is strictly better than all previous matches. //If there are no other remaining candidates, we're done. if (candidates == 1 && !eliminated[i]) return i; //Eliminate those other candidates from consideration. objectCanWin = eliminated[i]; for (int j = 0; j < i; j++) if (fparams[j] != null && !eliminated[j]){ bool noFormalForCurrParam = fparams[j].Length <= p; if (noFormalForCurrParam && parameters <= p) //Do not eliminate an overload if it does not have a formal for the current position //and the call does not have an actual parameter for the current position either. continue; if (noFormalForCurrParam || !objectCanWin || !JSBinder.FormalParamTypeIsObject(fparams[j][p])) eliminated[j] = true; } minval = distance; } } if (p >= parameters-1 && candidatesWithFormalParametersStillToBeConsidered < 1) //Looked at all actual parameters as well as all formal parameters, no further progress can be made break; } int best = -1; for (int j = 0; j < matches && candidates > 0; j++){ ParameterInfo[] fpars = fparams[j]; if (fpars != null){ if (eliminated[j]){ candidates--; fparams[j] = null; continue; } int pc = fpars.Length; if (best == -1){ //Choose the first remaining candidate as "best" best = j; continue; } if (Class.ParametersMatch(fpars, fparams[best])){ MemberInfo bstm = match[best]; JSWrappedMethod jswm = match[best] as JSWrappedMethod; if (jswm != null) bstm = jswm.method; if (bstm is JSFieldMethod || bstm is JSConstructor || bstm is JSProperty){ //The first match is always the most derived, go with it candidates--; fparams[j] = null; continue; } Type bestMemT = match[best].DeclaringType; Type memT = match[j].DeclaringType; if (bestMemT != memT){ if (memT.IsAssignableFrom(bestMemT)){ candidates--; fparams[j] = null; continue; }else if (bestMemT.IsAssignableFrom(memT)){ fparams[best] = null; best = j; candidates--; continue; } } } } } if (candidates != 1) throw new AmbiguousMatchException(); return best; }