8017045: anti-delta fix for 8013789
authorchegar
Wed, 19 Jun 2013 11:48:05 +0100
changeset 18412 d0e713f5cabd
parent 18410 daf2e2653da5
child 18413 5052b6314aad
8017045: anti-delta fix for 8013789 Reviewed-by: alanb
langtools/src/share/classes/com/sun/tools/javac/code/Types.java
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
langtools/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java
langtools/test/tools/javac/lambda/methodReference/BridgeMethod.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Jun 19 11:48:05 2013 +0100
@@ -33,15 +33,10 @@
 import java.util.Set;
 import java.util.WeakHashMap;
 
-import javax.tools.JavaFileObject;
-
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
-import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Check;
-import com.sun.tools.javac.comp.Enter;
-import com.sun.tools.javac.comp.Env;
 import com.sun.tools.javac.jvm.ClassReader;
 import com.sun.tools.javac.util.*;
 import static com.sun.tools.javac.code.BoundKind.*;
@@ -88,7 +83,6 @@
     final boolean allowDefaultMethods;
     final ClassReader reader;
     final Check chk;
-    final Enter enter;
     JCDiagnostic.Factory diags;
     List<Warner> warnStack = List.nil();
     final Name capturedName;
@@ -115,7 +109,6 @@
         allowDefaultMethods = source.allowDefaultMethods();
         reader = ClassReader.instance(context);
         chk = Check.instance(context);
-        enter = Enter.instance(context);
         capturedName = names.fromString("<captured wildcard>");
         messages = JavacMessages.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
@@ -610,84 +603,6 @@
             return site;
         }
     }
-
-    /**
-     * Create a symbol for a class that implements a given functional interface
-     * and overrides its functional descriptor. This routine is used for two
-     * main purposes: (i) checking well-formedness of a functional interface;
-     * (ii) perform functional interface bridge calculation.
-     */
-    public ClassSymbol makeFunctionalInterfaceClass(Env<AttrContext> env, Name name, List<Type> targets, long cflags) {
-        Assert.check(targets.nonEmpty() && isFunctionalInterface(targets.head));
-        Symbol descSym = findDescriptorSymbol(targets.head.tsym);
-        Type descType = findDescriptorType(targets.head);
-        ClassSymbol csym = new ClassSymbol(cflags, name, env.enclClass.sym.outermostClass());
-        csym.completer = null;
-        csym.members_field = new Scope(csym);
-        MethodSymbol instDescSym = new MethodSymbol(descSym.flags(), descSym.name, descType, csym);
-        csym.members_field.enter(instDescSym);
-        Type.ClassType ctype = new Type.ClassType(Type.noType, List.<Type>nil(), csym);
-        ctype.supertype_field = syms.objectType;
-        ctype.interfaces_field = targets;
-        csym.type = ctype;
-        csym.sourcefile = ((ClassSymbol)csym.owner).sourcefile;
-        return csym;
-    }
-
-    /**
-     * Find the minimal set of methods that are overridden by the functional
-     * descriptor in 'origin'. All returned methods are assumed to have different
-     * erased signatures.
-     */
-    public List<Symbol> functionalInterfaceBridges(TypeSymbol origin) {
-        Assert.check(isFunctionalInterface(origin));
-        Symbol descSym = findDescriptorSymbol(origin);
-        CompoundScope members = membersClosure(origin.type, false);
-        ListBuffer<Symbol> overridden = ListBuffer.lb();
-        outer: for (Symbol m2 : members.getElementsByName(descSym.name, bridgeFilter)) {
-            if (m2 == descSym) continue;
-            else if (descSym.overrides(m2, origin, Types.this, false)) {
-                for (Symbol m3 : overridden) {
-                    if (isSameType(m3.erasure(Types.this), m2.erasure(Types.this)) ||
-                            (m3.overrides(m2, origin, Types.this, false) &&
-                            (pendingBridges((ClassSymbol)origin, m3.enclClass()) ||
-                            (((MethodSymbol)m2).binaryImplementation((ClassSymbol)m3.owner, Types.this) != null)))) {
-                        continue outer;
-                    }
-                }
-                overridden.add(m2);
-            }
-        }
-        return overridden.toList();
-    }
-    //where
-        private Filter<Symbol> bridgeFilter = new Filter<Symbol>() {
-            public boolean accepts(Symbol t) {
-                return t.kind == Kinds.MTH &&
-                        t.name != names.init &&
-                        t.name != names.clinit &&
-                        (t.flags() & SYNTHETIC) == 0;
-            }
-        };
-        private boolean pendingBridges(ClassSymbol origin, TypeSymbol s) {
-            //a symbol will be completed from a classfile if (a) symbol has
-            //an associated file object with CLASS kind and (b) the symbol has
-            //not been entered
-            if (origin.classfile != null &&
-                    origin.classfile.getKind() == JavaFileObject.Kind.CLASS &&
-                    enter.getEnv(origin) == null) {
-                return false;
-            }
-            if (origin == s) {
-                return true;
-            }
-            for (Type t : interfaces(origin.type)) {
-                if (pendingBridges((ClassSymbol)t.tsym, s)) {
-                    return true;
-                }
-            }
-            return false;
-        }
     // </editor-fold>
 
    /**
@@ -2728,7 +2643,6 @@
                 public boolean accepts(Symbol s) {
                     return s.kind == Kinds.MTH &&
                             s.name == msym.name &&
-                            (s.flags() & SYNTHETIC) == 0 &&
                             s.isInheritedIn(site.tsym, Types.this) &&
                             overrideEquivalent(memberType(site, s), memberType(site, msym));
                 }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jun 19 11:48:05 2013 +0100
@@ -2327,12 +2327,13 @@
             if (pt() != Type.recoveryType) {
                 target = targetChecker.visit(target, that);
                 lambdaType = types.findDescriptorType(target);
+                chk.checkFunctionalInterface(that, target);
             } else {
                 target = Type.recoveryType;
                 lambdaType = fallbackDescriptorType(that);
             }
 
-            setFunctionalInfo(localEnv, that, pt(), lambdaType, target, resultInfo.checkContext);
+            setFunctionalInfo(that, pt(), lambdaType, target, resultInfo.checkContext.inferenceContext());
 
             if (lambdaType.hasTag(FORALL)) {
                 //lambda expression target desc cannot be a generic method
@@ -2674,12 +2675,13 @@
             if (pt() != Type.recoveryType) {
                 target = targetChecker.visit(pt(), that);
                 desc = types.findDescriptorType(target);
+                chk.checkFunctionalInterface(that, target);
             } else {
                 target = Type.recoveryType;
                 desc = fallbackDescriptorType(that);
             }
 
-            setFunctionalInfo(localEnv, that, pt(), desc, target, resultInfo.checkContext);
+            setFunctionalInfo(that, pt(), desc, target, resultInfo.checkContext.inferenceContext());
             List<Type> argtypes = desc.getParameterTypes();
 
             Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
@@ -2881,37 +2883,31 @@
      * might contain inference variables, we might need to register an hook in the
      * current inference context.
      */
-    private void setFunctionalInfo(final Env<AttrContext> env, final JCFunctionalExpression fExpr,
-            final Type pt, final Type descriptorType, final Type primaryTarget, final CheckContext checkContext) {
-        if (checkContext.inferenceContext().free(descriptorType)) {
-            checkContext.inferenceContext().addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
+    private void setFunctionalInfo(final JCFunctionalExpression fExpr, final Type pt,
+            final Type descriptorType, final Type primaryTarget, InferenceContext inferenceContext) {
+        if (inferenceContext.free(descriptorType)) {
+            inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() {
                 public void typesInferred(InferenceContext inferenceContext) {
-                    setFunctionalInfo(env, fExpr, pt, inferenceContext.asInstType(descriptorType),
-                            inferenceContext.asInstType(primaryTarget), checkContext);
+                    setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType),
+                            inferenceContext.asInstType(primaryTarget), inferenceContext);
                 }
             });
         } else {
-            ListBuffer<Type> targets = ListBuffer.lb();
+            ListBuffer<TypeSymbol> targets = ListBuffer.lb();
             if (pt.hasTag(CLASS)) {
                 if (pt.isCompound()) {
-                    targets.append(types.removeWildcards(primaryTarget)); //this goes first
+                    targets.append(primaryTarget.tsym); //this goes first
                     for (Type t : ((IntersectionClassType)pt()).interfaces_field) {
                         if (t != primaryTarget) {
-                            targets.append(types.removeWildcards(t));
+                            targets.append(t.tsym);
                         }
                     }
                 } else {
-                    targets.append(types.removeWildcards(primaryTarget));
+                    targets.append(pt.tsym);
                 }
             }
             fExpr.targets = targets.toList();
-            if (checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK &&
-                    pt != Type.recoveryType) {
-                //check that functional interface class is well-formed
-                ClassSymbol csym = types.makeFunctionalInterfaceClass(env,
-                        names.empty, List.of(fExpr.targets.head), ABSTRACT);
-                chk.checkImplementations(env.tree, csym, csym);
-            }
+            fExpr.descriptorType = descriptorType;
         }
     }
 
@@ -4567,6 +4563,9 @@
         @Override
         public void visitLambda(JCLambda that) {
             super.visitLambda(that);
+            if (that.descriptorType == null) {
+                that.descriptorType = syms.unknownType;
+            }
             if (that.targets == null) {
                 that.targets = List.nil();
             }
@@ -4578,6 +4577,9 @@
             if (that.sym == null) {
                 that.sym = new MethodSymbol(0, names.empty, syms.unknownType, syms.noSymbol);
             }
+            if (that.descriptorType == null) {
+                that.descriptorType = syms.unknownType;
+            }
             if (that.targets == null) {
                 that.targets = List.nil();
             }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jun 19 11:48:05 2013 +0100
@@ -2267,6 +2267,24 @@
         c.flags_field |= ACYCLIC;
     }
 
+    /**
+     * Check that functional interface methods would make sense when seen
+     * from the perspective of the implementing class
+     */
+    void checkFunctionalInterface(JCTree tree, Type funcInterface) {
+        ClassType c = new ClassType(Type.noType, List.<Type>nil(), null);
+        ClassSymbol csym = new ClassSymbol(0, names.empty, c, syms.noSymbol);
+        c.interfaces_field = List.of(types.removeWildcards(funcInterface));
+        c.supertype_field = syms.objectType;
+        c.tsym = csym;
+        csym.members_field = new Scope(csym);
+        Symbol descSym = types.findDescriptorSymbol(funcInterface.tsym);
+        Type descType = types.findDescriptorType(funcInterface);
+        csym.members_field.enter(new MethodSymbol(PUBLIC, descSym.name, descType, csym));
+        csym.completer = null;
+        checkImplementations(tree, csym, csym);
+    }
+
     /** Check that all methods which implement some
      *  method conform to the method they implement.
      *  @param tree         The class definition whose members are checked.
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Jun 19 11:48:05 2013 +0100
@@ -100,9 +100,6 @@
     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
     public static final int FLAG_MARKERS = 1 << 1;
 
-    /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
-    public static final int FLAG_BRIDGES = 1 << 2;
-
     private class KlassInfo {
 
         /**
@@ -324,7 +321,7 @@
         int refKind = referenceKind(sym);
 
         //convert to an invokedynamic call
-        result = makeMetaFactoryIndyCall(context, refKind, sym, indy_args);
+        result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
     }
 
     private JCIdent makeThis(Type type, Symbol owner) {
@@ -385,7 +382,7 @@
 
 
         //build a sam instance using an indy call to the meta-factory
-        result = makeMetaFactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
+        result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
     }
 
     /**
@@ -911,11 +908,10 @@
     /**
      * Generate an indy method call to the meta factory
      */
-    private JCExpression makeMetaFactoryIndyCall(TranslationContext<?> context,
-            int refKind, Symbol refSym, List<JCExpression> indy_args) {
-        JCFunctionalExpression tree = context.tree;
+    private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
+            boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
         //determine the static bsm args
-        Type mtype = types.erasure(tree.getDescriptorType(types));
+        Type mtype = types.erasure(tree.descriptorType);
         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
         List<Object> staticArgs = List.<Object>of(
                 new Pool.MethodHandle(ClassFile.REF_invokeInterface,
@@ -938,40 +934,25 @@
                 List.<Type>nil(),
                 syms.methodClass);
 
-        Name metafactoryName = context.needsAltMetafactory() ?
+        Name metafactoryName = needsAltMetafactory ?
                 names.altMetaFactory : names.metaFactory;
 
-        if (context.needsAltMetafactory()) {
+        if (needsAltMetafactory) {
             ListBuffer<Object> markers = ListBuffer.lb();
-            for (Type t : tree.targets.tail) {
-                if (t.tsym != syms.serializableType.tsym) {
-                    markers.append(t.tsym);
+            for (Symbol t : tree.targets.tail) {
+                if (t != syms.serializableType.tsym) {
+                    markers.append(t);
                 }
             }
-            int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
+            int flags = isSerializable? FLAG_SERIALIZABLE : 0;
             boolean hasMarkers = markers.nonEmpty();
-            boolean hasBridges = context.bridges.nonEmpty();
-            if (hasMarkers) {
-                flags |= FLAG_MARKERS;
-            }
-            if (hasBridges) {
-                flags |= FLAG_BRIDGES;
-            }
+            flags |= hasMarkers ? FLAG_MARKERS : 0;
             staticArgs = staticArgs.append(flags);
             if (hasMarkers) {
                 staticArgs = staticArgs.append(markers.length());
                 staticArgs = staticArgs.appendList(markers.toList());
             }
-            if (hasBridges) {
-                staticArgs = staticArgs.append(context.bridges.length() - 1);
-                for (Symbol s : context.bridges) {
-                    Type s_erasure = s.erasure(types);
-                    if (!types.isSameType(s_erasure, samSym.erasure(types))) {
-                        staticArgs = staticArgs.append(s.erasure(types));
-                    }
-                }
-            }
-            if (context.isSerializable()) {
+            if (isSerializable) {
                 addDeserializationCase(refKind, refSym, tree.type, samSym,
                         tree, staticArgs, indyType);
             }
@@ -1318,6 +1299,7 @@
 
                 // Make lambda holding the new-class call
                 JCLambda slam = make.Lambda(params, nc);
+                slam.descriptorType = tree.descriptorType;
                 slam.targets = tree.targets;
                 slam.type = tree.type;
                 slam.pos = tree.pos;
@@ -1652,30 +1634,23 @@
             /** the enclosing translation context (set for nested lambdas/mref) */
             TranslationContext<?> prev;
 
-            /** list of methods to be bridged by the meta-factory */
-            List<Symbol> bridges;
-
             TranslationContext(T tree) {
                 this.tree = tree;
                 this.owner = owner();
                 this.depth = frameStack.size() - 1;
                 this.prev = context();
-                ClassSymbol csym =
-                        types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
-                this.bridges = types.functionalInterfaceBridges(csym);
             }
 
             /** does this functional expression need to be created using alternate metafactory? */
             boolean needsAltMetafactory() {
-                return tree.targets.length() > 1 ||
-                        isSerializable() ||
-                        bridges.length() > 1;
+                return (tree.targets.length() > 1 ||
+                        isSerializable());
             }
 
             /** does this functional expression require serialization support? */
             boolean isSerializable() {
-                for (Type target : tree.targets) {
-                    if (types.asSuper(target, syms.serializableType.tsym) != null) {
+                for (Symbol target : tree.targets) {
+                    if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
                         return true;
                     }
                 }
@@ -1858,7 +1833,7 @@
             }
 
             Type generatedLambdaSig() {
-                return types.erasure(tree.getDescriptorType(types));
+                return types.erasure(tree.descriptorType);
             }
         }
 
@@ -1934,7 +1909,7 @@
             }
 
             Type bridgedRefSig() {
-                return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
+                return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
             }
         }
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Wed Jun 19 11:48:05 2013 +0100
@@ -68,7 +68,6 @@
     private TreeMaker make;
     private Enter enter;
     private boolean allowEnums;
-    private boolean allowInterfaceBridges;
     private Types types;
     private final Resolve resolve;
 
@@ -92,7 +91,6 @@
         Source source = Source.instance(context);
         allowEnums = source.allowEnums();
         addBridges = source.addBridges();
-        allowInterfaceBridges = source.allowDefaultMethods();
         types = Types.instance(context);
         make = TreeMaker.instance(context);
         resolve = Resolve.instance(context);
@@ -254,8 +252,7 @@
 
         // Create a bridge method symbol and a bridge definition without a body.
         Type bridgeType = meth.erasure(types);
-        long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE |
-                (origin.isInterface() ? DEFAULT : 0);
+        long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE;
         if (hypothetical) flags |= HYPOTHETICAL;
         MethodSymbol bridge = new MethodSymbol(flags,
                                                meth.name,
@@ -390,12 +387,11 @@
         }
     }
     // where
-        private Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
+        Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
             public boolean accepts(Symbol s) {
                 return (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC;
             }
         };
-
         /**
          * @param method The symbol for which a bridge might have to be added
          * @param impl The implementation of method
@@ -1003,9 +999,8 @@
                     ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
                     if (false) //see CR: 6996415
                         bridges.appendList(addOverrideBridgesIfNeeded(tree, c));
-                    if (allowInterfaceBridges || (tree.sym.flags() & INTERFACE) == 0) {
-                        addBridges(tree.pos(), c, bridges);
-                    }
+                    if ((tree.sym.flags() & INTERFACE) == 0)
+                        addBridges(tree.pos(), tree.sym, bridges);
                     tree.defs = bridges.toList().prependList(tree.defs);
                 }
                 tree.type = erasure(tree.type);
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Jun 19 11:48:05 2013 +0100
@@ -641,12 +641,10 @@
             polyKind = PolyKind.POLY;
         }
 
+        /** target descriptor inferred for this functional expression. */
+        public Type descriptorType;
         /** list of target types inferred for this functional expression. */
-        public List<Type> targets;
-
-        public Type getDescriptorType(Types types) {
-            return types.findDescriptorType(targets.head);
-        }
+        public List<TypeSymbol> targets;
     }
 
     /**
--- a/langtools/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java	Wed Jun 19 11:48:05 2013 +0100
@@ -105,7 +105,7 @@
             Class returnType = m.getReturnType();
             assertTrue(types.remove(returnType.getName()));
         }
-        assertTrue(types.size() == 1); //there's a bridge
+        assertTrue(types.isEmpty());
     }
 
 
--- a/langtools/test/tools/javac/lambda/methodReference/BridgeMethod.java	Tue Jun 18 20:56:04 2013 -0700
+++ b/langtools/test/tools/javac/lambda/methodReference/BridgeMethod.java	Wed Jun 19 11:48:05 2013 +0100
@@ -112,6 +112,6 @@
             Class<?> returnType = m.getReturnType();
             assertTrue(types.remove(returnType.getName()));
         }
-        assertTrue(types.size() == 1); //there's a bridge
+        assertTrue(types.isEmpty());
     }
 }