diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-10-26 16:24:36 -0400 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-10-26 16:24:36 -0400 |
commit | 91c9d60398d2187b433b2b296ba25fa312344e7e (patch) | |
tree | ff4cf5318acf601e0fdadd12b7525ae5a6a817fe | |
parent | 6fae6b41cc61657340b075b49b85e05753b8b321 (diff) |
generate bridge methods for covariant returns
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 119 |
1 files changed, 89 insertions, 30 deletions
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index e2657776..67111ef1 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -4986,6 +4986,9 @@ static public class NewInstanceExpr extends ObjExpr{ //IPersistentMap optionsMap = PersistentArrayMap.EMPTY; IPersistentCollection methods; + Map<IPersistentVector,java.lang.reflect.Method> mmap; + Map<IPersistentVector,Set<Class>> covariants; + public NewInstanceExpr(Object tag){ super(tag); } @@ -5083,7 +5086,10 @@ static public class NewInstanceExpr extends ObjExpr{ Class superClass = Object.class; Map[] mc = gatherMethods(superClass,RT.seq(interfaces)); Map overrideables = mc[0]; - Map allmethods = mc[1]; + Map covariants = mc[1]; + ret.mmap = overrideables; + ret.covariants = covariants; + String[] inames = interfaceNames(interfaces); Symbol thistag = null; @@ -5112,7 +5118,7 @@ static public class NewInstanceExpr extends ObjExpr{ IPersistentCollection methods = null; for(ISeq s = methodForms; s != null; s = RT.next(s)) { - NewInstanceMethod m = NewInstanceMethod.parse(ret, (ISeq) RT.first(s),thistag, overrideables, allmethods); + NewInstanceMethod m = NewInstanceMethod.parse(ret, (ISeq) RT.first(s),thistag, overrideables); methods = RT.conj(methods, m); } @@ -5204,48 +5210,102 @@ static public class NewInstanceExpr extends ObjExpr{ ObjMethod method = (ObjMethod) s.first(); method.emit(this, cv); } + //emit bridge methods + for(Map.Entry<IPersistentVector,Set<Class>> e : covariants.entrySet()) + { + java.lang.reflect.Method m = mmap.get(e.getKey()); + Class[] params = m.getParameterTypes(); + Type[] argTypes = new Type[params.length]; + + for(int i = 0; i < params.length; i++) + { + argTypes[i] = Type.getType(params[i]); + } + + Method target = new Method(m.getName(), Type.getType(m.getReturnType()), argTypes); + + for(Class retType : e.getValue()) + { + Method meth = new Method(m.getName(), Type.getType(retType), argTypes); + + GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC + ACC_BRIDGE, + meth, + null, + //todo don't hardwire this + EXCEPTION_TYPES, + cv); + gen.visitCode(); + gen.loadThis(); + gen.loadArgs(); + gen.invokeInterface(Type.getType(m.getDeclaringClass()),target); + gen.returnValue(); + gen.endMethod(); + } + } } static public IPersistentVector msig(java.lang.reflect.Method m){ - return RT.vector(m.getName(), RT.seq(m.getParameterTypes())); + return RT.vector(m.getName(), RT.seq(m.getParameterTypes()),m.getReturnType()); } - static void considerMethod(java.lang.reflect.Method m, Map mm, Map considered){ + static void considerMethod(java.lang.reflect.Method m, Map mm){ IPersistentVector mk = msig(m); int mods = m.getModifiers(); - if(considered.containsKey(mk) - || !(Modifier.isPublic(mods) || Modifier.isProtected(mods)) - || Modifier.isStatic(mods) - || Modifier.isFinal(mods)) + if(!(mm.containsKey(mk) + || !(Modifier.isPublic(mods) || Modifier.isProtected(mods)) + || Modifier.isStatic(mods) + || Modifier.isFinal(mods))) { - if(!Modifier.isStatic(mods)) - considered.put(mk, m); - } - else - { - considered.put(mk, m); - mm.put(mk, m); + mm.put(mk, m); } } - static void gatherMethods(Class c, Map mm, Map considered){ + static void gatherMethods(Class c, Map mm){ for(; c != null; c = c.getSuperclass()) { for(java.lang.reflect.Method m : c.getDeclaredMethods()) - considerMethod(m, mm, considered); + considerMethod(m, mm); for(java.lang.reflect.Method m : c.getMethods()) - considerMethod(m, mm, considered); + considerMethod(m, mm); } } static public Map[] gatherMethods(Class sc, ISeq interfaces){ - Map mm = new HashMap(); - Map considered = new HashMap(); - gatherMethods(sc, mm, considered); + Map allm = new HashMap(); + gatherMethods(sc, allm); for(; interfaces != null; interfaces = interfaces.next()) - gatherMethods((Class) interfaces.first(), mm, considered); - return new Map[]{mm, considered}; + gatherMethods((Class) interfaces.first(), allm); + + Map<IPersistentVector,java.lang.reflect.Method> mm = new HashMap<IPersistentVector,java.lang.reflect.Method>(); + Map<IPersistentVector,Set<Class>> covariants = new HashMap<IPersistentVector,Set<Class>>(); + for(Object o : allm.entrySet()) + { + Map.Entry e = (Map.Entry) o; + IPersistentVector mk = (IPersistentVector) e.getKey(); + mk = (IPersistentVector) mk.pop(); + java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue(); + if(mm.containsKey(mk)) //covariant return + { + Set<Class> cvs = covariants.get(mk); + if(cvs == null) + { + cvs = new HashSet<Class>(); + covariants.put(mk,cvs); + } + java.lang.reflect.Method om = mm.get(mk); + if(om.getReturnType().isAssignableFrom(m.getReturnType())) + { + cvs.add(om.getReturnType()); + mm.put(mk, m); + } + else + cvs.add(m.getReturnType()); + } + else + mm.put(mk, m); + } + return new Map[]{mm,covariants}; } } @@ -5282,7 +5342,7 @@ public static class NewInstanceMethod extends ObjMethod{ } static NewInstanceMethod parse(ObjExpr objx, ISeq form, Symbol thistag, - Map overrideables, Map allmethods) throws Exception{ + Map overrideables) throws Exception{ //(methodname [args] body...) NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod) METHOD.deref()); Symbol name = (Symbol)RT.first(form); @@ -5350,9 +5410,9 @@ public static class NewInstanceMethod extends ObjMethod{ if(m == null) throw new IllegalArgumentException("Can't find matching method: " + name.name + ", leave off hints for auto match."); - if(m.getReturnType() != method.retClass) - throw new IllegalArgumentException("Mismatched return type: " + name.name + - ", expected: " + m.getReturnType().getName() + ", had: " + method.retClass.getName()); + if(m.getReturnType() != method.retClass) + throw new IllegalArgumentException("Mismatched return type: " + name.name + + ", expected: " + m.getReturnType().getName() + ", had: " + method.retClass.getName()); } else //adopt found method sig { @@ -5362,9 +5422,8 @@ public static class NewInstanceMethod extends ObjMethod{ } } } - else if(findMethodsWithName(name.name,allmethods).size()>0) - throw new IllegalArgumentException("Can't override/overload method: " + name.name); - //todo +// else if(findMethodsWithName(name.name,allmethods).size()>0) +// throw new IllegalArgumentException("Can't override/overload method: " + name.name); else throw new IllegalArgumentException("Can't define method not in interfaces: " + name.name); |