From c00317220523c42ae0cc459fa3526c641e37f2af Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 23 Jul 2020 23:33:27 +0200 Subject: [bugfix] [javac] LUB types + val Until recently, we'd 'resolve' LUB (compound) types in val constructs by just taking the first one in the line of interfaces. The problem is, different versions of different compilers use different orderings. In an earlier commit, the eclipse impl gained a new algorithm that is more stable, e.g. by sorting on alphabet. now the javac side has the same algorithm. --- src/core/lombok/javac/JavacResolution.java | 62 ++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) (limited to 'src/core') diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index 9a0077a7..98bf3c4b 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -28,7 +28,10 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Iterator; import java.util.Map; +import java.util.NoSuchElementException; import javax.lang.model.type.TypeKind; import javax.tools.JavaFileObject; @@ -40,6 +43,7 @@ import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.ArrayType; import com.sun.tools.javac.code.Type.CapturedType; import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.Type.TypeVar; import com.sun.tools.javac.code.Type.WildcardType; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.comp.Attr; @@ -59,6 +63,7 @@ import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Name; import lombok.Lombok; import lombok.core.debug.AssertionLogger; @@ -314,6 +319,37 @@ public class JavacResolution { return result; } + private static Iterable concat(final Type t, final Collection ts) { + if (t == null) return ts; + + return new Iterable() { + @Override public Iterator iterator() { + return new Iterator() { + private boolean first = true; + private Iterator wrap = ts == null ? null : ts.iterator(); + @Override public boolean hasNext() { + if (first) return true; + if (wrap == null) return false; + return wrap.hasNext(); + } + + @Override public Type next() { + if (first) { + first = false; + return t; + } + if (wrap == null) throw new NoSuchElementException(); + return wrap.next(); + } + }; + } + }; + } + + private static int compare(Name a, Name b) { + return a.compareTo(b); + } + private static JCExpression typeToJCTree0(Type type, JavacAST ast, boolean allowCompound, boolean allowVoid, boolean allowCapture) throws TypeNotConvertibleException { // NB: There's such a thing as maker.Type(type), but this doesn't work very well; it screws up anonymous classes, captures, and adds an extra prefix dot for some reason too. // -- so we write our own take on that here. @@ -335,12 +371,30 @@ public class JavacResolution { if (symbol.name.length() == 0) { // Anonymous inner class if (type instanceof ClassType) { - List ifaces = ((ClassType) type).interfaces_field; + Type winner = null; + int winLevel = 0; // 100 = array, 50 = class, 20 = typevar, 15 = wildcard, 10 = interface, 1 = Object. Type supertype = ((ClassType) type).supertype_field; - if (isObject(supertype) && ifaces != null && ifaces.length() > 0) { - return typeToJCTree(ifaces.get(0), ast, allowCompound, allowVoid, allowCapture); + List ifaces = ((ClassType) type).interfaces_field; + for (Type t : concat(supertype, ifaces)) { + int level = 0; + if (t instanceof ArrayType) level = 100; + else if (t instanceof TypeVar) level = 20; + else if (t instanceof WildcardType) level = 15; + else if (t.isInterface()) level = 10; + else if (isObject(t)) level = 1; + else if (t instanceof ClassType) level = 50; + else level = 5; + + if (winLevel > level) continue; + if (winLevel < level) { + winner = t; + winLevel = level; + continue; + } + if (compare(winner.tsym.getQualifiedName(), t.tsym.getQualifiedName()) < 0) winner = t; } - if (supertype != null) return typeToJCTree(supertype, ast, allowCompound, allowVoid, allowCapture); + if (winner == null) return createJavaLangObject(ast); + return typeToJCTree(winner, ast, allowCompound, allowVoid, allowCapture); } throw new TypeNotConvertibleException("Anonymous inner class"); } -- cgit