summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2009-07-30 18:36:25 -0400
committerRich Hickey <richhickey@gmail.com>2009-07-30 18:36:25 -0400
commite35c4688f30a542d3585e72cfe9bc66936ca5afe (patch)
tree99d067812e041c03d8ad51dbe2dcdfb5954752ce /src
parent3c15d0eb6bdc279c801dd984a3524666d7c5cfbe (diff)
added signature inference, overload detection
Diffstat (limited to 'src')
-rw-r--r--src/jvm/clojure/lang/Compiler.java150
1 files changed, 138 insertions, 12 deletions
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index cc239723..79fd6c61 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -4866,6 +4866,10 @@ static public class NewInstanceExpr extends ObjExpr{
superClass = Object.class;
superAndInterfaces = RT.cons(superClass, superAndInterfaces);
}
+ ISeq interfaces = RT.next(superAndInterfaces);
+ Map[] mc = gatherMethods(superClass,interfaces);
+ Map overrideables = mc[0];
+ Map allmethods = mc[1];
ISeq rform = RT.next(RT.next(form));
@@ -4895,7 +4899,7 @@ static public class NewInstanceExpr extends ObjExpr{
IPersistentCollection methods = null;
for(ISeq s = rform; s != null; s = RT.next(s))
{
- NewInstanceMethod m = NewInstanceMethod.parse(ret, (ISeq) RT.first(s));
+ NewInstanceMethod m = NewInstanceMethod.parse(ret, (ISeq) RT.first(s),overrideables, allmethods);
methods = RT.conj(methods, m);
}
@@ -4930,6 +4934,48 @@ static public class NewInstanceExpr extends ObjExpr{
method.emit(this, cv);
}
}
+
+ static public IPersistentVector msig(java.lang.reflect.Method m){
+ return RT.vector(m.getName(), RT.seq(m.getParameterTypes()));
+ }
+
+ static void considerMethod(java.lang.reflect.Method m, Map mm, Map considered){
+ 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(!Modifier.isStatic(mods))
+ considered.put(mk, m);
+ }
+ else
+ {
+ considered.put(mk, m);
+ mm.put(mk, m);
+ }
+ }
+
+ static void gatherMethods(Class c, Map mm, Map considered){
+ for(; c != null; c = c.getSuperclass())
+ {
+ for(java.lang.reflect.Method m : c.getDeclaredMethods())
+ considerMethod(m, mm, considered);
+ for(java.lang.reflect.Method m : c.getMethods())
+ considerMethod(m, mm, considered);
+ }
+ }
+
+ static public Map[] gatherMethods(Class sc, ISeq interfaces){
+ Map mm = new HashMap();
+ Map considered = new HashMap();
+ gatherMethods(sc, mm, considered);
+ for(; interfaces != null; interfaces = interfaces.next())
+ gatherMethods((Class) interfaces.first(), mm, considered);
+ return new Map[]{mm, considered};
+ }
}
public static class NewInstanceMethod extends ObjMethod{
@@ -4993,8 +5039,12 @@ public static class NewInstanceMethod extends ObjMethod{
c = HostExpr.tagToClass(tag);
return c;
}
-
- static NewInstanceMethod parse(ObjExpr objx, ISeq form) throws Exception{
+
+ static public IPersistentVector msig(String name,Class[] paramTypes){
+ return RT.vector(name,RT.seq(paramTypes));
+ }
+
+ static NewInstanceMethod parse(ObjExpr objx, ISeq form, Map overrideables, Map allmethods) throws Exception{
//(methodname [args] body...)
NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod) METHOD.deref());
Symbol name = (Symbol)RT.first(form);
@@ -5016,21 +5066,78 @@ public static class NewInstanceMethod extends ObjMethod{
PersistentVector argLocals = PersistentVector.EMPTY;
method.retClass = tagClass(tagOf(name));
- method.retType = Type.getType(method.retClass);
method.argTypes = new Type[parms.count()];
+ boolean hinted = tagOf(name) != null;
+ Class[] pclasses = new Class[parms.count()];
+ Symbol[] psyms = new Symbol[parms.count()];
+
for(int i = 0; i < parms.count(); i++)
{
if(!(parms.nth(i) instanceof Symbol))
throw new IllegalArgumentException("params must be Symbols");
Symbol p = (Symbol) parms.nth(i);
Object tag = tagOf(p);
+ if(tag != null)
+ hinted = true;
if(p.getNamespace() != null)
p = Symbol.create(p.name);
Class pclass = tagClass(tag);
- LocalBinding lb = registerLocal(p, null, new MethodParamExpr(pclass));
+ pclasses[i] = pclass;
+ psyms[i] = p;
+ }
+ Map matches = findMethodsWithNameAndArity(name.name, parms.count(), overrideables);
+ Object mk = msig(name.name, pclasses);
+ if(matches.size() > 0)
+ {
+ //multiple methods
+ if(matches.size() > 1)
+ {
+ //must be hinted and match one method
+ if(!hinted)
+ throw new IllegalArgumentException("Must hint overloaded method: " + name.name);
+ java.lang.reflect.Method m = (java.lang.reflect.Method) matches.get(mk);
+ if(m == null)
+ throw new IllegalArgumentException("Can't find matching overloaded method: " + name.name);
+ if(m.getReturnType() != method.retClass)
+ throw new IllegalArgumentException("Mismatched return type: " + name.name +
+ ", expected: " + m.getReturnType().getName() + ", had: " + method.retClass.getName());
+ }
+ else //one match
+ {
+ //if hinted, validate match,
+ if(hinted)
+ {
+ java.lang.reflect.Method m = (java.lang.reflect.Method) matches.get(mk);
+ 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());
+ }
+ else //adopt found method sig
+ {
+ java.lang.reflect.Method m = (java.lang.reflect.Method) matches.values().iterator().next();
+ method.retClass = m.getReturnType();
+ pclasses = m.getParameterTypes();
+ }
+ }
+ }
+ else if(findMethodsWithName(name.name,allmethods).size()>0)
+ throw new IllegalArgumentException("Can't override/overload method: " + name.name);
+ //todo
+ //else
+ //validate unque name+arity among additional methods
+
+ method.retType = Type.getType(method.retClass);
+
+ for(int i = 0; i < parms.count(); i++)
+ {
+ LocalBinding lb = registerLocal(psyms[i], null, new MethodParamExpr(pclasses[i]));
argLocals = argLocals.assocN(i,lb);
- method.argTypes[i] = Type.getType(pclass);
+ method.argTypes[i] = Type.getType(pclasses[i]);
}
+
LOOP_LOCALS.set(argLocals);
method.name = name.name;
method.argLocals = argLocals;
@@ -5043,6 +5150,30 @@ public static class NewInstanceMethod extends ObjMethod{
}
}
+ private static Map findMethodsWithNameAndArity(String name, int arity, Map mm){
+ Map ret = new HashMap();
+ for(Object o : mm.entrySet())
+ {
+ Map.Entry e = (Map.Entry) o;
+ java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue();
+ if(name.equals(m.getName()) && m.getParameterTypes().length == arity)
+ ret.put(e.getKey(), e.getValue());
+ }
+ return ret;
+ }
+
+ private static Map findMethodsWithName(String name, Map mm){
+ Map ret = new HashMap();
+ for(Object o : mm.entrySet())
+ {
+ Map.Entry e = (Map.Entry) o;
+ java.lang.reflect.Method m = (java.lang.reflect.Method) e.getValue();
+ if(name.equals(m.getName()))
+ ret.put(e.getKey(), e.getValue());
+ }
+ return ret;
+ }
+
public void emit(ObjExpr obj, ClassVisitor cv){
Method m = new Method(getMethodName(), getReturnType(), getArgTypes());
@@ -5134,10 +5265,5 @@ static public class MethodParamExpr implements Expr, MaybePrimitiveExpr{
}
}
-static void gatherMethods(Class c, Map mm, Set considered){
- for(;c != null;c = c.getSuperclass())
- {
-
- }
-}
+
}