[ductilej] push by samskivert - Improve overload handling in the absence of correct type information. ... on 2010-07-10 18:12 GMT

1 view
Skip to first unread message

duct...@googlecode.com

unread,
Jul 10, 2010, 2:13:01 PM7/10/10
to ductil...@googlegroups.com
Revision: 049d0cb010
Author: Michael Bayne <m...@samskivert.com>
Date: Sat Jul 10 11:12:13 2010
Log: Improve overload handling in the absence of correct type information.
Follow
the JLS in preferring exact matches to those requiring subtype conversion
and
those requiring subtype conversion to those requiring boxing or widening
conversion.
http://code.google.com/p/ductilej/source/detail?r=049d0cb010

Modified:
/src/org/ductilej/runtime/RT.java

=======================================
--- /src/org/ductilej/runtime/RT.java Fri Jul 9 15:54:45 2010
+++ /src/org/ductilej/runtime/RT.java Sat Jul 10 11:12:13 2010
@@ -815,12 +815,6 @@
Class<?> parent = clazz.getSuperclass();
return (parent == null) ? null : findMethod(parent, mname, atypes);
}
-
- protected static class MethodData
- {
- public Method best;
- public boolean typeMatch;
- }

/**
* Resolves the best matching method given the supplied runtime
argument types. This is used
@@ -852,14 +846,16 @@
continue;
}

- boolean typeMatch = argTypeMatch(
+ int match = argTypeMatch(
Arrays.asList(ptypes), isMangled, method.isVarArgs(),
atypes);
-
- if ((mdata.best == null) || (typeMatch && !mdata.typeMatch)) {
+ if (match == 0) {
+ // no match, keep looking
+
+ } else if (match > mdata.match) {
mdata.best = method;
- mdata.typeMatch = typeMatch;
-
- } else if (typeMatch && mdata.typeMatch) {
+ mdata.match = match;
+
+ } else if (match == mdata.match) {
// if the argument types are exactly the same and the
declaring class differs,
// we're just seeing a parent method that has been
overridden by our best match
if (!mdata.best.getDeclaringClass().equals(clazz) &&
@@ -869,8 +865,7 @@
throw new AmbiguousMethodError(
Debug.format("Two methods (or more) with matching
types", "mname", mname,
"atypes", atypes, "m1", mdata.best, "m2",
method));
-
- } // else: 'best' is a type match and the current method is
not, so we skip it
+ } // else: keep our existing match, it's closer
}

Class<?> parent = clazz.getSuperclass();
@@ -966,7 +961,7 @@
Class<?> clazz, boolean needsOuterThis, boolean isMangled,
Object[] args)
{
Constructor<?> best = null;
- boolean bestTypeMatch = false;
+ int bestMatch = 0;

Class<?>[] atypes = toArgTypes(args);
for (Constructor<?> ctor : clazz.getDeclaredConstructors()) {
@@ -980,18 +975,19 @@
continue;
}

- boolean typeMatch = argTypeMatch(ptypes, isMangled,
ctor.isVarArgs(), atypes);
-
- if (best == null || (typeMatch && !bestTypeMatch)) {
+ int match = argTypeMatch(ptypes, isMangled, ctor.isVarArgs(),
atypes);
+ if (match == 0) {
+ // no match, keep looking
+
+ } else if (match > bestMatch) {
best = ctor;
-
- } else if (typeMatch && bestTypeMatch) {
+ bestMatch = match;
+
+ } else if (match == bestMatch) {
throw new AmbiguousMethodError(
- Debug.format("Two ctors (or more) with matching types",
- "clazz", clazz.getName(), "atypes",
atypes,
- "c1", best, "c2", ctor));
-
- } // else: 'best' is a type match and the current method is
not, so we skip it
+ Debug.format("Two (or more) matching ctors", "clazz",
clazz.getName(),
+ "atypes", atypes, "c1", best, "c2",
ctor));
+ } // else: existing match is better, move it along
}

return best;
@@ -1009,17 +1005,32 @@
return (pcount == acount) || (isVarArgs && (pcount-1) <= acount);
}

- protected static boolean argTypeMatch (
+ protected static int argTypeMatch (
List<Class<?>> ptypes, boolean isMangled, boolean isVarArgs,
Class<?>[] atypes)
{
- // make sure all fixed arity arguments match
+ // determine whether all fixed arity arguments match
int pcount = isMangled ? ptypes.size()/2 : ptypes.size();
int fpcount = isVarArgs ? pcount-1 : pcount, poff = isMangled ?
pcount : 0;
+ int match = 3; // assume exact match
for (int ii = 0; ii < fpcount; ii++) {
- Class<?> ptype = /*boxType(*/ptypes.get(poff + ii)/*)*/;
- if (atypes[ii] != null && !isAssignableFrom(ptype,
atypes[ii])) {
- return false;
- }
+ Class<?> atype = atypes[ii];
+ if (atype == null) {
+ continue;
+ }
+ Class<?> ptype = ptypes.get(poff + ii);
+ if (atype == ptype) {
+ continue; // exact match, no conversion demotion
+ }
+ if (ptype.isAssignableFrom(atype)) {
+ match = Math.min(2, match); // reduce to subtype conversion
+ continue;
+ }
+ if (boxType(ptype).equals(atype) ||
+ (ptype.isPrimitive() && COERCIONS.containsEntry(atype,
ptype))) {
+ match = Math.min(1, match); // reduce to boxing conversion
+ continue;
+ }
+ return 0; // argument mismatch
}

// TODO: should we leave this out, or is there some better check we can do
given that detyped
@@ -1035,15 +1046,7 @@
// }
// }
// }
- return true;
- }
-
- protected static boolean isAssignableFrom (Class<?> ptype, Class<?>
atype)
- {
- return ptype.isAssignableFrom(atype) || // widening reference
conversion
- boxType(ptype).equals(atype) || // boxing conversion
- (ptype.isPrimitive() && // widening primitve
conversion
- COERCIONS.containsEntry(atype, ptype));
+ return match;
}

/**
@@ -1232,6 +1235,13 @@
return "(" + left + "," + right + ")";
}
}
+
+ /** Used to resolve the closest matching method or ctor. */
+ protected static class MethodData
+ {
+ public Method best;
+ public int match;
+ }

/** Used to coerce primitive types. */
protected static interface Coercer {

Reply all
Reply to author
Forward
0 new messages