diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 6324456fa1..0bae0f6d54 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1165,12 +1165,17 @@ static class QualifiedMethodExpr implements Expr { private final String methodName; private final MethodKind kind; private final Class tagClass; + private final StaticFieldExpr fieldOverload; private enum MethodKind { CTOR, INSTANCE, STATIC } - public QualifiedMethodExpr(Class methodClass, Symbol sym){ + public QualifiedMethodExpr(Class methodClass, Symbol sym) { + this(methodClass, sym, null); + } + + public QualifiedMethodExpr(Class methodClass, Symbol sym, StaticFieldExpr fieldOL) { c = methodClass; methodSymbol = sym; tagClass = tagOf(sym) != null ? HostExpr.tagToClass(tagOf(sym)) : AFn.class; @@ -1187,18 +1192,29 @@ else if(sym.name.equals("new")) { kind = MethodKind.STATIC; methodName = sym.name; } + fieldOverload = fieldOL; + } + + private boolean preferOverloadedField() { + return fieldOverload != null && paramTagsOf(methodSymbol) == null; } // Expr impl - invocation, convert to fn expr @Override public Object eval() { - return buildThunk(C.EVAL, this).eval(); + if(preferOverloadedField()) + return fieldOverload.eval(); + else + return buildThunk(C.EVAL, this).eval(); } @Override public void emit(C context, ObjExpr objx, GeneratorAdapter gen) { - buildThunk(context, this).emit(context, objx, gen); + if(preferOverloadedField()) + fieldOverload.emit(context, objx, gen); + else + buildThunk(context, this).emit(context, objx, gen); } // Expr impl - method value, always an AFn @@ -1258,18 +1274,9 @@ private static Set aritySet(Class c, String methodName, MethodKind kind) { return res; } - // Returns a list of methods or ctors matching the name and kind given. - // Otherwise, will throw if the information provided results in no matches - private static List methodsWithName(Class c, String methodName, MethodKind kind) { - if (kind == MethodKind.CTOR) { - List ctors = Arrays.asList(c.getConstructors()); - if(ctors.isEmpty()) - throw noMethodWithNameException(c, methodName, kind); - return ctors; - } - + public static List methodOverloads(Class c, String methodName, MethodKind kind) { final Executable[] methods = c.getMethods(); - List res = Arrays.stream(methods) + return Arrays.stream(methods) .filter(m -> m.getName().equals(methodName)) .filter(m -> { switch(kind) { @@ -1279,6 +1286,19 @@ private static List methodsWithName(Class c, String methodName, Meth } }) .collect(Collectors.toList()); + } + + // Returns a list of methods or ctors matching the name and kind given. + // Otherwise, will throw if the information provided results in no matches + private static List methodsWithName(Class c, String methodName, MethodKind kind) { + if (kind == MethodKind.CTOR) { + List ctors = Arrays.asList(c.getConstructors()); + if(ctors.isEmpty()) + throw noMethodWithNameException(c, methodName, kind); + return ctors; + } + + List res = methodOverloads(c, methodName, kind); if(res.isEmpty()) throw noMethodWithNameException(c, methodName, kind); @@ -4115,7 +4135,7 @@ static Object sigTag(int argcount, Var v){ return tagOf(sig); } return null; - } + } public InvokeExpr(String source, int line, int column, Symbol tag, Expr fexpr, IPersistentVector args, boolean tailPosition) { this.source = source; @@ -4359,18 +4379,26 @@ static public Expr parse(C context, ISeq form) { (KeywordExpr) fexpr, target); } - // Preserving the existing static field bug that replaces a reference in parens with - // the field itself rather than trying to invoke the value in the field. This is - // an exception to the uniform Class/member qualification per CLJ-2806 ticket. - if(fexpr instanceof StaticFieldExpr) - return fexpr; - PersistentVector args = PersistentVector.EMPTY; for(ISeq s = RT.seq(form.next()); s != null; s = s.next()) { args = args.cons(analyze(context, s.first())); } + // Preserving the existing static field syntax that replaces a reference in parens with + // the field itself rather than trying to invoke the value in the field. This is + // an exception to the uniform Class/member qualification per CLJ-2806 ticket. + if(fexpr instanceof StaticFieldExpr) + { + if(RT.count(args) == 0) + return fexpr; + else + throw new IllegalArgumentException("No matching method " + + ((StaticFieldExpr) fexpr).fieldName + + " found taking " + RT.count(args) + " args for " + + ((StaticFieldExpr) fexpr).c); + } + if(fexpr instanceof QualifiedMethodExpr) return toHostExpr((QualifiedMethodExpr)fexpr, (String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), tailPosition, args); @@ -7830,7 +7858,14 @@ private static Expr analyzeSymbol(Symbol sym) { if(c != null) { if(Reflector.getField(c, sym.name, true) != null) - return new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag); + { + List maybeOverloads = QualifiedMethodExpr.methodOverloads(c, sym.name, QualifiedMethodExpr.MethodKind.STATIC); + + if(maybeOverloads.isEmpty()) + return new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag); + else + return new QualifiedMethodExpr(c, sym, new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag)); + } else return new QualifiedMethodExpr(c, sym); } diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj index fee2d1c53e..bccd3ef127 100644 --- a/test/clojure/test_clojure/param_tags.clj +++ b/test/clojure/test_clojure/param_tags.clj @@ -170,6 +170,30 @@ :instance (let [{:keys [expected actual]} (exercise-instance-method m)] (is (= expected actual)))))) +(deftest field-overloads-method-CLJ-2899-regression + (testing "overloaded in value position" + (is (= "static-field" clojure.test.SwissArmy/doppelganger))) + + (testing "overloaded in value position, w/paramtags" + (is (= "" (apply ^[] clojure.test.SwissArmy/doppelganger [])))) + + (testing "overloaded, invoke no args" + (is (= "" (clojure.test.SwissArmy/doppelganger)))) + + (testing "overloaded, invoke w/args" + (is (= "int-int-long" (clojure.test.SwissArmy/doppelganger (int 1) (int 2) (long 42))))) + + (testing "non-overloaded, field holds IFn, invoke w/args fails" + (is (thrown? Exception (eval '(clojure.test.SwissArmy/idFn 42)))) + (is (= #'clojure.core/identity clojure.test.SwissArmy/idFn))) + + (testing "non-overloaded, field holds IFn, invoke no args" + (is (= #'clojure.core/identity (clojure.test.SwissArmy/idFn)))) + + (testing "instance method overloads" + (is (= "int-int" (clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2)))) + (is (= "int-int" (apply clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2) []))))) + (defmacro arg-tags-called-in-macro [a-type b-type a b] `(^[~a-type ~b-type] SwissArmy/staticArityOverloadMethod ~a ~b)) diff --git a/test/java/clojure/test/SwissArmy.java b/test/java/clojure/test/SwissArmy.java index 339c3723c4..f38e2d44f5 100644 --- a/test/java/clojure/test/SwissArmy.java +++ b/test/java/clojure/test/SwissArmy.java @@ -1,7 +1,12 @@ package clojure.test; +import clojure.java.api.Clojure; +import clojure.lang.IFn; + public class SwissArmy { + public static String doppelganger = "static-field"; public String ctorId; + public static IFn idFn = Clojure.var("clojure.core", "identity"); public SwissArmy() {this.ctorId = "1";} public SwissArmy(int a, long b) {this.ctorId = "2";} @@ -36,4 +41,5 @@ public class SwissArmy { public static String staticArityOverloadMethod(int a, int b) {return "int-int";} public static String staticArityOverloadMethod(int a, int b, int c) {return "int-int-int";} public static String doppelganger(int a, int b, long c) {return "int-int-long";} -} \ No newline at end of file + public static String doppelganger() {return "";} +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy