Fixing bug 255549: proper resolution of overloaded methods.

This commit is contained in:
igor%mir2.org 2004-08-13 19:31:32 +00:00
Родитель 0fa9344f94
Коммит 3a68eb5402
1 изменённых файлов: 108 добавлений и 97 удалений

Просмотреть файл

@ -254,130 +254,140 @@ public class NativeJavaMethod extends BaseFunction
return 0; return 0;
} }
int bestFit = -1; int firstBestFit = -1;
Class[] bestFitTypes = null; int[] extraBestFits = null;
int extraBestFitsCount = 0;
int[] ambiguousMethods = null;
int ambiguousMethodCount = 0;
search:
for (int i = 0; i < methodsOrCtors.length; i++) { for (int i = 0; i < methodsOrCtors.length; i++) {
MemberBox member = methodsOrCtors[i]; MemberBox member = methodsOrCtors[i];
Class[] argTypes = member.argTypes; Class[] argTypes = member.argTypes;
if (argTypes.length != args.length) { if (argTypes.length != args.length) {
continue; continue search;
} }
if (bestFit < 0) { for (int j = 0; j < argTypes.length; j++) {
int j; if (!NativeJavaObject.canConvert(args[j], argTypes[j])) {
for (j = 0; j < argTypes.length; j++) { if (debug) printDebug("Rejecting (args can't convert) ",
if (!NativeJavaObject.canConvert(args[j], argTypes[j])) { member, args);
if (debug) printDebug("Rejecting (args can't convert) ", continue search;
member, args); }
break; }
if (firstBestFit < 0) {
if (debug) printDebug("Found first applicable ", member, args);
firstBestFit = i;
} else {
// Compare with all currently fit methods.
// The loop starts from -1 denoting firstBestFit and proceed
// until extraBestFitsCount to avoid extraBestFits allocation
// in the most common case of no ambiguity
int betterCount = 0; // number of times member was prefered over
// best fits
int worseCount = 0; // number of times best fits were prefered
// over member
for (int j = -1; j != extraBestFitsCount; ++j) {
int bestFitIndex;
if (j == -1) {
bestFitIndex = firstBestFit;
} else {
bestFitIndex = extraBestFits[j];
} }
} MemberBox bestFit = methodsOrCtors[bestFitIndex];
if (j == argTypes.length) { int preference = preferSignature(args, argTypes,
if (debug) printDebug("Found ", member, args); bestFit.argTypes);
bestFit = i; if (preference == PREFERENCE_AMBIGUOUS) {
bestFitTypes = argTypes; break;
} } else if (preference == PREFERENCE_FIRST_ARG) {
} ++betterCount;
else { } else if (preference == PREFERENCE_SECOND_ARG) {
int preference = preferSignature(args, argTypes, ++worseCount;
bestFitTypes); } else {
if (preference == PREFERENCE_AMBIGUOUS) { if (preference != PREFERENCE_EQUAL) Kit.codeBug();
if (debug) printDebug("Deferring ", member, args); // This should not happen in theory
// add to "ambiguity list" // but on some JVMs, Class.getMethods will return all
if (ambiguousMethods == null)
ambiguousMethods = new int[methodsOrCtors.length];
ambiguousMethods[ambiguousMethodCount++] = i;
} else if (preference == PREFERENCE_FIRST_ARG) {
if (debug) printDebug("Substituting ", member, args);
bestFit = i;
bestFitTypes = argTypes;
} else if (preference == PREFERENCE_SECOND_ARG) {
if (debug) printDebug("Rejecting ", member, args);
} else {
if (preference != PREFERENCE_EQUAL) Kit.codeBug();
MemberBox best = methodsOrCtors[bestFit];
if (best.isStatic()
&& best.getDeclaringClass().isAssignableFrom(
member.getDeclaringClass()))
{
// On some JVMs, Class.getMethods will return all
// static methods of the class heirarchy, even if // static methods of the class heirarchy, even if
// a derived class's parameters match exactly. // a derived class's parameters match exactly.
// We want to call the dervied class's method. // We want to call the dervied class's method.
if (debug) printDebug( if (bestFit.isStatic()
"Substituting (overridden static)", member, args); && bestFit.getDeclaringClass().isAssignableFrom(
bestFit = i; member.getDeclaringClass()))
bestFitTypes = argTypes; {
} else { // On some JVMs, Class.getMethods will return all
if (debug) printDebug( // static methods of the class heirarchy, even if
"Ignoring same signature member ", member, args); // a derived class's parameters match exactly.
// We want to call the dervied class's method.
if (debug) printDebug(
"Substituting (overridden static)",
member, args);
if (j == -1) {
firstBestFit = i;
} else {
extraBestFits[j] = i;
}
} else {
if (debug) printDebug(
"Ignoring same signature member ",
member, args);
}
continue search;
} }
} }
if (betterCount == 1 + extraBestFitsCount) {
// member was prefered over all best fits
if (debug) printDebug(
"New first applicable ", member, args);
firstBestFit = i;
extraBestFitsCount = 0;
} else if (worseCount == 1 + extraBestFitsCount) {
// all best fits were prefered over member, ignore it
if (debug) printDebug(
"Rejecting (all current bests better) ", member, args);
} else {
// some ambiguity was present, add member to best fit set
if (debug) printDebug(
"Added to best fit set ", member, args);
if (extraBestFits == null) {
// Allocate maximum possible array
extraBestFits = new int[methodsOrCtors.length - 1];
}
extraBestFits[extraBestFitsCount] = i;
++extraBestFitsCount;
}
} }
} }
if (ambiguousMethodCount == 0) if (firstBestFit < 0) {
return bestFit; // Nothing was found
return -1;
// Compare ambiguous methods with best fit, in case } else if (extraBestFitsCount == 0) {
// the current best fit removes the ambiguities. // single best fit
int removedCount = 0; return firstBestFit;
for (int k = 0; k != ambiguousMethodCount; ++k) {
int i = ambiguousMethods[k];
MemberBox member = methodsOrCtors[i];
Class[] argTypes = member.argTypes;
int preference = preferSignature(args, argTypes,
bestFitTypes);
if (preference == PREFERENCE_FIRST_ARG) {
if (debug) printDebug("Substituting ", member, args);
bestFit = i;
bestFitTypes = argTypes;
ambiguousMethods[k] = -1;
++removedCount;
}
else if (preference == PREFERENCE_SECOND_ARG) {
if (debug) printDebug("Rejecting ", member, args);
ambiguousMethods[k] = -1;
++removedCount;
}
else {
if (debug) printDebug("UNRESOLVED: ", member, args);
}
} }
if (removedCount == ambiguousMethodCount) { // report remaining ambiguity
return bestFit;
}
// PENDING: report remaining ambiguity
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
for (int j = -1; j != extraBestFitsCount; ++j) {
ambiguousMethods[ambiguousMethodCount++] = bestFit; int bestFitIndex;
boolean first = true; if (j == -1) {
for (int k = 0; k < ambiguousMethodCount; k++) { bestFitIndex = firstBestFit;
int i = ambiguousMethods[k]; } else {
if (i < 0) { continue; } bestFitIndex = extraBestFits[j];
if (!first) {
buf.append(", ");
} }
buf.append(methodsOrCtors[i].toJavaDeclaration()); buf.append("\n ");
first = false; buf.append(methodsOrCtors[bestFitIndex].toJavaDeclaration());
} }
MemberBox best = methodsOrCtors[bestFit]; MemberBox firstFitMember = methodsOrCtors[firstBestFit];
String memberName = firstFitMember.getName();
String memberClass = firstFitMember.getDeclaringClass().getName();
if (methodsOrCtors[0].isMethod()) { if (methodsOrCtors[0].isMethod()) {
throw Context.reportRuntimeError3( throw Context.reportRuntimeError3(
"msg.constructor.ambiguous", "msg.constructor.ambiguous",
best.getName(), scriptSignature(args), buf.toString()); memberName, scriptSignature(args), buf.toString());
} else { } else {
throw Context.reportRuntimeError4( throw Context.reportRuntimeError4(
"msg.method.ambiguous", best.getDeclaringClass().getName(), "msg.method.ambiguous", memberClass,
best.getName(), scriptSignature(args), buf.toString()); memberName, scriptSignature(args), buf.toString());
} }
} }
@ -468,6 +478,7 @@ public class NativeJavaMethod extends BaseFunction
sb.append(" for arguments ("); sb.append(" for arguments (");
sb.append(scriptSignature(args)); sb.append(scriptSignature(args));
sb.append(')'); sb.append(')');
System.out.println(sb);
} }
} }