8016281: The SAM method should be passed to the metafactory as a MethodType not a MethodHandle
authormcimadamore
Thu, 11 Jul 2013 14:07:39 +0100
changeset 18730 95354d510139
parent 18729 89ecb9d4d654
child 18731 38dd7ede2dfb
child 18920 5111c1aa3ecd
8016281: The SAM method should be passed to the metafactory as a MethodType not a MethodHandle 8020010: Move lambda bridge creation from metafactory and VM to compiler Summary: langtools/javac component of the bridge support and MethodType vs. MethodHandle changes. Reviewed-by: jjg, vromero, briangoetz, forax Contributed-by: robert.field@oracle.com
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/src/share/classes/com/sun/tools/javac/util/Names.java
langtools/test/tools/javac/generics/bridges/Bridge.java
langtools/test/tools/javac/generics/bridges/BridgeHarness.java
langtools/test/tools/javac/generics/bridges/Bridges.java
langtools/test/tools/javac/generics/bridges/tests/TestBridgeWithDefault.java
langtools/test/tools/javac/generics/bridges/tests/TestClassAndInterfaceBridgeIdentical01.java
langtools/test/tools/javac/generics/bridges/tests/TestClassAndInterfaceBridgeIdentical02.java
langtools/test/tools/javac/generics/bridges/tests/TestNoBridgeInSiblingsSuper.java
langtools/test/tools/javac/generics/bridges/tests/TestNoDuplicateBridges01.java
langtools/test/tools/javac/generics/bridges/tests/TestNoDuplicateBridges02.java
langtools/test/tools/javac/lambda/bridge/TestMetafactoryBridges.java
langtools/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java
langtools/test/tools/javac/lambda/methodReference/BridgeMethod.java
langtools/test/tools/javac/lambdaShapes/org/openjdk/tests/vm/DefaultMethodsTest.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Jul 11 14:07:39 2013 +0100
@@ -33,10 +33,15 @@
 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.*;
@@ -83,6 +88,7 @@
     final boolean allowDefaultMethods;
     final ClassReader reader;
     final Check chk;
+    final Enter enter;
     JCDiagnostic.Factory diags;
     List<Warner> warnStack = List.nil();
     final Name capturedName;
@@ -109,6 +115,7 @@
         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);
@@ -605,6 +612,84 @@
             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>
 
    /**
@@ -2672,6 +2757,7 @@
                 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	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Jul 11 14:07:39 2013 +0100
@@ -2334,13 +2334,12 @@
             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(that, pt(), lambdaType, target, resultInfo.checkContext.inferenceContext());
+            setFunctionalInfo(localEnv, that, pt(), lambdaType, target, resultInfo.checkContext);
 
             if (lambdaType.hasTag(FORALL)) {
                 //lambda expression target desc cannot be a generic method
@@ -2682,13 +2681,12 @@
             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(that, pt(), desc, target, resultInfo.checkContext.inferenceContext());
+            setFunctionalInfo(localEnv, that, pt(), desc, target, resultInfo.checkContext);
             List<Type> argtypes = desc.getParameterTypes();
 
             Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
@@ -2890,31 +2888,37 @@
      * might contain inference variables, we might need to register an hook in the
      * current inference context.
      */
-    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() {
+    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() {
                 public void typesInferred(InferenceContext inferenceContext) {
-                    setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType),
-                            inferenceContext.asInstType(primaryTarget), inferenceContext);
+                    setFunctionalInfo(env, fExpr, pt, inferenceContext.asInstType(descriptorType),
+                            inferenceContext.asInstType(primaryTarget), checkContext);
                 }
             });
         } else {
-            ListBuffer<TypeSymbol> targets = ListBuffer.lb();
+            ListBuffer<Type> targets = ListBuffer.lb();
             if (pt.hasTag(CLASS)) {
                 if (pt.isCompound()) {
-                    targets.append(primaryTarget.tsym); //this goes first
+                    targets.append(types.removeWildcards(primaryTarget)); //this goes first
                     for (Type t : ((IntersectionClassType)pt()).interfaces_field) {
                         if (t != primaryTarget) {
-                            targets.append(t.tsym);
+                            targets.append(types.removeWildcards(t));
                         }
                     }
                 } else {
-                    targets.append(pt.tsym);
+                    targets.append(types.removeWildcards(primaryTarget));
                 }
             }
             fExpr.targets = targets.toList();
-            fExpr.descriptorType = descriptorType;
+            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);
+            }
         }
     }
 
@@ -4579,9 +4583,6 @@
         @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();
             }
@@ -4593,9 +4594,6 @@
             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	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Jul 11 14:07:39 2013 +0100
@@ -2275,24 +2275,6 @@
         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	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Jul 11 14:07:39 2013 +0100
@@ -100,6 +100,9 @@
     /** 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 {
 
         /**
@@ -321,7 +324,7 @@
         int refKind = referenceKind(sym);
 
         //convert to an invokedynamic call
-        result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
+        result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
     }
 
     private JCIdent makeThis(Type type, Symbol owner) {
@@ -382,7 +385,7 @@
 
 
         //build a sam instance using an indy call to the meta-factory
-        result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
+        result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
     }
 
     /**
@@ -606,8 +609,8 @@
                 make.Return(makeIndyCall(
                     pos,
                     syms.lambdaMetafactory,
-                    names.altMetaFactory,
-                    staticArgs, indyType, serArgs.toList())),
+                    names.altMetafactory,
+                    staticArgs, indyType, serArgs.toList(), samSym.name)),
                 null);
         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
         if (stmts == null) {
@@ -905,22 +908,26 @@
         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
     }
 
+    private MethodType typeToMethodType(Type mt) {
+        Type type = types.erasure(mt);
+        return new MethodType(type.getParameterTypes(),
+                        type.getReturnType(),
+                        type.getThrownTypes(),
+                        syms.methodClass);
+    }
+
     /**
      * Generate an indy method call to the meta factory
      */
-    private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
-            boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
+    private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
+            int refKind, Symbol refSym, List<JCExpression> indy_args) {
+        JCFunctionalExpression tree = context.tree;
         //determine the static bsm args
-        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,
-                    types.findDescriptorSymbol(tree.type.tsym), types),
+                typeToMethodType(samSym.type),
                 new Pool.MethodHandle(refKind, refSym, types),
-                new MethodType(mtype.getParameterTypes(),
-                        mtype.getReturnType(),
-                        mtype.getThrownTypes(),
-                        syms.methodClass));
+                typeToMethodType(tree.getDescriptorType(types)));
 
         //computed indy arg types
         ListBuffer<Type> indy_args_types = ListBuffer.lb();
@@ -934,31 +941,46 @@
                 List.<Type>nil(),
                 syms.methodClass);
 
-        Name metafactoryName = needsAltMetafactory ?
-                names.altMetaFactory : names.metaFactory;
+        Name metafactoryName = context.needsAltMetafactory() ?
+                names.altMetafactory : names.metafactory;
 
-        if (needsAltMetafactory) {
+        if (context.needsAltMetafactory()) {
             ListBuffer<Object> markers = ListBuffer.lb();
-            for (Symbol t : tree.targets.tail) {
-                if (t != syms.serializableType.tsym) {
-                    markers.append(t);
+            for (Type t : tree.targets.tail) {
+                if (t.tsym != syms.serializableType.tsym) {
+                    markers.append(t.tsym);
                 }
             }
-            int flags = isSerializable? FLAG_SERIALIZABLE : 0;
+            int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
             boolean hasMarkers = markers.nonEmpty();
-            flags |= hasMarkers ? FLAG_MARKERS : 0;
+            boolean hasBridges = context.bridges.nonEmpty();
+            if (hasMarkers) {
+                flags |= FLAG_MARKERS;
+            }
+            if (hasBridges) {
+                flags |= FLAG_BRIDGES;
+            }
             staticArgs = staticArgs.append(flags);
             if (hasMarkers) {
                 staticArgs = staticArgs.append(markers.length());
                 staticArgs = staticArgs.appendList(markers.toList());
             }
-            if (isSerializable) {
+            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()) {
                 addDeserializationCase(refKind, refSym, tree.type, samSym,
                         tree, staticArgs, indyType);
             }
         }
 
-        return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
+        return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
     }
 
     /**
@@ -966,7 +988,8 @@
      * arguments types
      */
     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
-            List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
+            List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
+            Name methName) {
         int prevPos = make.pos;
         try {
             make.at(pos);
@@ -978,7 +1001,7 @@
                     bsmName, bsm_staticArgs, List.<Type>nil());
 
             DynamicMethodSymbol dynSym =
-                    new DynamicMethodSymbol(names.lambda,
+                    new DynamicMethodSymbol(methName,
                                             syms.noSymbol,
                                             bsm.isStatic() ?
                                                 ClassFile.REF_invokeStatic :
@@ -1299,7 +1322,6 @@
 
                 // 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;
@@ -1634,23 +1656,30 @@
             /** 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());
+                return tree.targets.length() > 1 ||
+                        isSerializable() ||
+                        bridges.length() > 1;
             }
 
             /** does this functional expression require serialization support? */
             boolean isSerializable() {
-                for (Symbol target : tree.targets) {
-                    if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
+                for (Type target : tree.targets) {
+                    if (types.asSuper(target, syms.serializableType.tsym) != null) {
                         return true;
                     }
                 }
@@ -1833,7 +1862,7 @@
             }
 
             Type generatedLambdaSig() {
-                return types.erasure(tree.descriptorType);
+                return types.erasure(tree.getDescriptorType(types));
             }
         }
 
@@ -1909,7 +1938,7 @@
             }
 
             Type bridgedRefSig() {
-                return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
+                return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
             }
         }
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Thu Jul 11 14:07:39 2013 +0100
@@ -68,6 +68,7 @@
     private TreeMaker make;
     private Enter enter;
     private boolean allowEnums;
+    private boolean allowInterfaceBridges;
     private Types types;
     private final Resolve resolve;
 
@@ -91,6 +92,7 @@
         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);
@@ -252,7 +254,8 @@
 
         // Create a bridge method symbol and a bridge definition without a body.
         Type bridgeType = meth.erasure(types);
-        long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE;
+        long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE |
+                (origin.isInterface() ? DEFAULT : 0);
         if (hypothetical) flags |= HYPOTHETICAL;
         MethodSymbol bridge = new MethodSymbol(flags,
                                                meth.name,
@@ -387,11 +390,12 @@
         }
     }
     // where
-        Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
+        private 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
@@ -999,8 +1003,9 @@
                     ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
                     if (false) //see CR: 6996415
                         bridges.appendList(addOverrideBridgesIfNeeded(tree, c));
-                    if ((tree.sym.flags() & INTERFACE) == 0)
-                        addBridges(tree.pos(), tree.sym, bridges);
+                    if (allowInterfaceBridges || (tree.sym.flags() & INTERFACE) == 0) {
+                        addBridges(tree.pos(), c, 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	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Thu Jul 11 14:07:39 2013 +0100
@@ -641,10 +641,12 @@
             polyKind = PolyKind.POLY;
         }
 
-        /** target descriptor inferred for this functional expression. */
-        public Type descriptorType;
         /** list of target types inferred for this functional expression. */
-        public List<TypeSymbol> targets;
+        public List<Type> targets;
+
+        public Type getDescriptorType(Types types) {
+            return types.findDescriptorType(targets.head);
+        }
     }
 
     /**
--- a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java	Thu Jul 11 14:07:39 2013 +0100
@@ -174,8 +174,8 @@
 
     //lambda-related
     public final Name lambda;
-    public final Name metaFactory;
-    public final Name altMetaFactory;
+    public final Name metafactory;
+    public final Name altMetafactory;
 
     public final Name.Table table;
 
@@ -310,8 +310,8 @@
 
         //lambda-related
         lambda = fromString("lambda$");
-        metaFactory = fromString("metaFactory");
-        altMetaFactory = fromString("altMetaFactory");
+        metafactory = fromString("metafactory");
+        altMetafactory = fromString("altMetafactory");
     }
 
     protected Name.Table createTable(Options options) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/Bridge.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.lang.annotation.Repeatable;
+
+@Repeatable(Bridges.class)
+@interface Bridge {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/BridgeHarness.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8013789
+ * @summary Compiler should emit bridges in interfaces
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor BridgeHarness
+ * @run main BridgeHarness
+ */
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.classfile.AccessFlags;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Method;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.util.List;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import static javax.tools.StandardLocation.*;
+
+public class BridgeHarness {
+
+    /** number of errors found (must be zero for the test to pass) */
+    static int nerrors = 0;
+
+    /** the (shared) Java compiler used for compiling the tests */
+    static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+
+    /** the (shared) file manager used by the compiler */
+    static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+    public static void main(String[] args) throws Exception {
+        //set sourcepath
+        fm.setLocation(SOURCE_PATH,
+                Arrays.asList(new File(System.getProperty("test.src"), "tests")));
+        //set output (-d)
+        fm.setLocation(javax.tools.StandardLocation.CLASS_OUTPUT,
+                Arrays.asList(new File(System.getProperty("user.dir"))));
+        for (JavaFileObject jfo : fm.list(SOURCE_PATH, "", Collections.singleton(JavaFileObject.Kind.SOURCE), true)) {
+            //for each source, compile and check against annotations
+            new BridgeHarness(jfo).compileAndCheck();
+        }
+        //if there were errors, fail
+        if (nerrors > 0) {
+            throw new AssertionError("Errors were found");
+        }
+    }
+
+    /* utility methods */
+
+    /**
+     * Remove an element from a list
+     */
+    static <Z> List<Z> drop(List<Z> lz, Z z) {
+        if (lz.head == z) {
+            return drop(lz.tail, z);
+        } else if (lz.isEmpty()) {
+            return lz;
+        } else {
+            return drop(lz.tail, z).prepend(lz.head);
+        }
+    }
+
+    /**
+     * return a string representation of a bytecode method
+     */
+    static String descriptor(Method m, ConstantPool cp) throws ConstantPoolException {
+        return m.getName(cp) + m.descriptor.getValue(cp);
+    }
+
+    /* test harness */
+
+    /** Test file to be compiled */
+    JavaFileObject jfo;
+
+    /** Mapping between class name and list of bridges in class with that name */
+    Map<String, List<Bridge>> bridgesMap = new HashMap<String, List<Bridge>>();
+
+    protected BridgeHarness(JavaFileObject jfo) {
+        this.jfo = jfo;
+    }
+
+    /**
+     * Compile a test using a custom annotation processor and check the generated
+     * bytecode against discovered annotations.
+     */
+    protected void compileAndCheck() throws Exception {
+        JavacTask ct = (JavacTask)comp.getTask(null, fm, null, null, null, Arrays.asList(jfo));
+        ct.setProcessors(Collections.singleton(new BridgeFinder()));
+
+        for (JavaFileObject jfo : ct.generate()) {
+            checkBridges(jfo);
+        }
+    }
+
+    /**
+     * Check that every bridge in the generated classfile has a matching bridge
+     * annotation in the bridge map
+     */
+    protected void checkBridges(JavaFileObject jfo) {
+        try {
+            ClassFile cf = ClassFile.read(jfo.openInputStream());
+            System.err.println("checking: " + cf.getName());
+
+            List<Bridge> bridgeList = bridgesMap.get(cf.getName());
+            if (bridgeList == null) {
+                //no bridges - nothing to check;
+                bridgeList = List.nil();
+            }
+
+            for (Method m : cf.methods) {
+                if (m.access_flags.is(AccessFlags.ACC_SYNTHETIC | AccessFlags.ACC_BRIDGE)) {
+                    //this is a bridge - see if there's a match in the bridge list
+                    Bridge match = null;
+                    for (Bridge b : bridgeList) {
+                        if (b.value().equals(descriptor(m, cf.constant_pool))) {
+                            match = b;
+                            break;
+                        }
+                    }
+                    if (match == null) {
+                        error("No annotation for bridge method: " + descriptor(m, cf.constant_pool));
+                    } else {
+                        bridgeList = drop(bridgeList, match);
+                    }
+                }
+            }
+            if (bridgeList.nonEmpty()) {
+                error("Redundant bridge annotation found: " + bridgeList.head.value());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new Error("error reading " + jfo.toUri() +": " + e);
+        }
+    }
+
+    /**
+     * Log an error
+     */
+    protected void error(String msg) {
+        nerrors++;
+        System.err.printf("Error occurred while checking file: %s\nreason: %s\n", jfo.getName(), msg);
+    }
+
+    /**
+     * This annotation processor is used to populate the bridge map with the
+     * contents of the annotations that are found on the tests being compiled
+     */
+    @SupportedAnnotationTypes({"Bridges","Bridge"})
+    class BridgeFinder extends JavacTestingAbstractProcessor {
+        @Override
+        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+            if (roundEnv.processingOver())
+                return true;
+
+            TypeElement bridgeAnno = elements.getTypeElement("Bridge");
+            TypeElement bridgesAnno = elements.getTypeElement("Bridges");
+
+            //see if there are repeated annos
+            for (Element elem: roundEnv.getElementsAnnotatedWith(bridgesAnno)) {
+                List<Bridge> bridgeList = List.nil();
+                Bridges bridges = elem.getAnnotation(Bridges.class);
+                for (Bridge bridge : bridges.value()) {
+                    bridgeList = bridgeList.prepend(bridge);
+                }
+                bridgesMap.put(((ClassSymbol)elem).flatname.toString(), bridgeList);
+            }
+
+            //see if there are non-repeated annos
+            for (Element elem: roundEnv.getElementsAnnotatedWith(bridgeAnno)) {
+                Bridge bridge = elem.getAnnotation(Bridge.class);
+                bridgesMap.put(((ClassSymbol)elem).flatname.toString(),
+                        List.of(bridge));
+            }
+
+            return true;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/Bridges.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+@interface Bridges {
+    Bridge[] value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/tests/TestBridgeWithDefault.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+class TestBridgeWithDefault {
+    interface A { Object m(int x); }
+
+    @Bridge("m(I)Ljava/lang/Object;")
+    interface B extends A {
+        String m(int x);
+        default Integer m(long x) { return null; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/tests/TestClassAndInterfaceBridgeIdentical01.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+class TestClassAndInterfaceBridgeIdentical01 {
+
+    interface A { Object m(); }
+    interface B { Number m(); }
+
+    @Bridge("m()Ljava/lang/Object;")
+    @Bridge("m()Ljava/lang/Number;")
+    interface C extends A, B {
+        Integer m();
+    }
+
+    @Bridge("m()Ljava/lang/Object;")
+    @Bridge("m()Ljava/lang/Number;")
+    static abstract class D implements A, B {
+        public abstract Integer m();
+    }
+
+    @Bridge("m()Ljava/lang/Object;")
+    @Bridge("m()Ljava/lang/Number;")
+    static class E implements A, B {
+        public Integer m() { return 1; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/tests/TestClassAndInterfaceBridgeIdentical02.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+class TestClassAndInterfaceBridgeIdentical02 {
+
+    interface A<X extends Object> { void m(X x); }
+    interface B<X extends Number> { void m(X x); }
+
+    @Bridge("m(Ljava/lang/Object;)V")
+    @Bridge("m(Ljava/lang/Number;)V")
+    interface C extends A<Integer>, B<Integer> {
+        void m(Integer i);
+    }
+
+    @Bridge("m(Ljava/lang/Object;)V")
+    @Bridge("m(Ljava/lang/Number;)V")
+    static abstract class D implements A<Integer>, B<Integer> {
+        public abstract void m(Integer i);
+    }
+
+    @Bridge("m(Ljava/lang/Object;)V")
+    @Bridge("m(Ljava/lang/Number;)V")
+    static class E implements A<Integer>, B<Integer> {
+        public void m(Integer i) { }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/tests/TestNoBridgeInSiblingsSuper.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+class TestNoBridgeInSiblingSuper {
+    interface A { Object m(); }
+    interface B { String m(); }
+    //no bridge here!
+    interface C extends A, B { }
+
+    @Bridge("m()Ljava/lang/Object;")
+    interface D extends C {
+        String m();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/tests/TestNoDuplicateBridges01.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+class TestNoDuplicateBridges01 {
+    interface A1 { Object m(); }
+    interface A2 { Object m(); }
+
+    @Bridge("m()Ljava/lang/Object;")
+    interface B extends A1, A2 { B m(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/bridges/tests/TestNoDuplicateBridges02.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+class TestNoDuplicateBridges02 {
+    interface A<T> {
+        A<T> get();
+    }
+
+    @Bridge("get()LTestNoDuplicateBridges02$A;")
+    interface B<T> extends A<T> {
+        B<T> get();
+    }
+
+    @Bridge("get()LTestNoDuplicateBridges02$A;")
+    @Bridge("get()LTestNoDuplicateBridges02$B;")
+    interface C<T> extends A<T>, B<T> {
+        C<T> get();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/bridge/TestMetafactoryBridges.java	Thu Jul 11 14:07:39 2013 +0100
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8013789
+ * @summary Compiler should emit bridges in interfaces
+ */
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.util.JCDiagnostic;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class TestMetafactoryBridges {
+
+    static int checkCount = 0;
+
+    enum ClasspathKind {
+        NONE(),
+        B7(7, ClassKind.B),
+        A7(7, ClassKind.A),
+        B8(8, ClassKind.B),
+        A8(8, ClassKind.A);
+
+        int version;
+        ClassKind ck;
+
+        ClasspathKind() {
+            this(-1, null);
+        }
+
+        ClasspathKind(int version, ClassKind ck) {
+            this.version = version;
+            this.ck = ck;
+        }
+    }
+
+    enum PreferPolicy {
+        SOURCE("-Xprefer:source"),
+        NEWER("-Xprefer:newer");
+
+        String preferOpt;
+
+        PreferPolicy(String preferOpt) {
+            this.preferOpt = preferOpt;
+        }
+    }
+
+    enum SourcepathKind {
+        NONE,
+        A(ClassKind.A),
+        B(ClassKind.B),
+        C(ClassKind.C),
+        AB(ClassKind.A, ClassKind.B),
+        BC(ClassKind.B, ClassKind.C),
+        AC(ClassKind.A, ClassKind.C),
+        ABC(ClassKind.A, ClassKind.B, ClassKind.C);
+
+        List<ClassKind> sources;
+
+        SourcepathKind(ClassKind... sources) {
+            this.sources = Arrays.asList(sources);
+        }
+    }
+
+    enum SourceSet {
+        ALL() {
+            @Override
+            List<List<ClassKind>> permutations() {
+                return Arrays.asList(
+                    Arrays.asList(ClassKind.A, ClassKind.B, ClassKind.C),
+                    Arrays.asList(ClassKind.A, ClassKind.B, ClassKind.C),
+                    Arrays.asList(ClassKind.B, ClassKind.A, ClassKind.C),
+                    Arrays.asList(ClassKind.B, ClassKind.C, ClassKind.A),
+                    Arrays.asList(ClassKind.C, ClassKind.A, ClassKind.B),
+                    Arrays.asList(ClassKind.C, ClassKind.B, ClassKind.A)
+                );
+            }
+        },
+        AC() {
+            @Override
+            List<List<ClassKind>> permutations() {
+                return Arrays.asList(
+                    Arrays.asList(ClassKind.A, ClassKind.C),
+                    Arrays.asList(ClassKind.C, ClassKind.A)
+                );
+            }
+        },
+        C() {
+            @Override
+            List<List<ClassKind>> permutations() {
+                return Arrays.asList(Arrays.asList(ClassKind.C));
+            }
+        };
+
+        abstract List<List<ClassKind>> permutations();
+    }
+
+    enum ClassKind {
+        A("A", "interface A { Object m(); }"),
+        B("B", "interface B extends A { Integer m(); }", A),
+        C("C", "class C { B b = ()->42; }", A, B);
+
+        String name;
+        String source;
+        ClassKind[] deps;
+
+        ClassKind(String name, String source, ClassKind... deps) {
+            this.name = name;
+            this.source = source;
+            this.deps = deps;
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+        String SCRATCH_DIR = System.getProperty("user.dir");
+        //create default shared JavaCompiler - reused across multiple compilations
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+
+        int n = 0;
+        for (SourceSet ss : SourceSet.values()) {
+            for (List<ClassKind> sources : ss.permutations()) {
+                for (SourcepathKind spKind : SourcepathKind.values()) {
+                    for (ClasspathKind cpKind : ClasspathKind.values()) {
+                        for (PreferPolicy pp : PreferPolicy.values()) {
+                            Set<ClassKind> deps = EnumSet.noneOf(ClassKind.class);
+                            if (cpKind.ck != null) {
+                                deps.add(cpKind.ck);
+                            }
+                            deps.addAll(sources);
+                            if (deps.size() < 3) continue;
+                            File testDir = new File(SCRATCH_DIR, "test" + n);
+                            testDir.mkdir();
+                            try (PrintWriter debugWriter = new PrintWriter(new File(testDir, "debug.txt"))) {
+                                new TestMetafactoryBridges(testDir, sources, spKind, cpKind, pp, debugWriter).run(comp);
+                                n++;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("Total check executed: " + checkCount);
+    }
+
+    File testDir;
+    List<ClassKind> sources;
+    SourcepathKind spKind;
+    ClasspathKind cpKind;
+    PreferPolicy pp;
+    PrintWriter debugWriter;
+    DiagnosticChecker diagChecker;
+
+    TestMetafactoryBridges(File testDir, List<ClassKind>sources, SourcepathKind spKind,
+            ClasspathKind cpKind, PreferPolicy pp, PrintWriter debugWriter) {
+        this.testDir = testDir;
+        this.sources = sources;
+        this.spKind = spKind;
+        this.cpKind = cpKind;
+        this.pp = pp;
+        this.debugWriter = debugWriter;
+        this.diagChecker = new DiagnosticChecker();
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        final String source;
+
+        public JavaSource(ClassKind ck) {
+            super(URI.create(String.format("myfo:/%s.java", ck.name)), JavaFileObject.Kind.SOURCE);
+            this.source = ck.source;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    void run(JavaCompiler tool) throws Exception {
+        File classesDir = new File(testDir, "classes");
+        File outDir = new File(testDir, "out");
+        File srcDir = new File(testDir, "src");
+        classesDir.mkdir();
+        outDir.mkdir();
+        srcDir.mkdir();
+
+        debugWriter.append(testDir.getName() + "\n");
+        debugWriter.append("sources = " + sources + "\n");
+        debugWriter.append("spKind = " + spKind  + "\n");
+        debugWriter.append("cpKind = " + cpKind + "\n");
+        debugWriter.append("preferPolicy = " + pp.preferOpt + "\n");
+
+        //step 1 - prepare sources (older!!)
+        debugWriter.append("Preparing sources\n");
+        for (ClassKind ck : spKind.sources) {
+            //skip sources explicitly provided on command line
+            if (!sources.contains(ck)) {
+                debugWriter.append("Copy " + ck.name + ".java to" + srcDir.getAbsolutePath() + "\n");
+                File dest = new File(srcDir, ck.name + ".java");
+                PrintWriter pw = new PrintWriter(dest);
+                pw.append(ck.source);
+                pw.close();
+            }
+        }
+
+        //step 2 - prepare classes
+        debugWriter.append("Preparing classes\n");
+        if (cpKind != ClasspathKind.NONE) {
+            List<JavaSource> sources = new ArrayList<>();
+            ClassKind toRemove = null;
+            sources.add(new JavaSource(cpKind.ck));
+            if (cpKind.ck.deps.length != 0) {
+                //at most only one dependency
+                toRemove = cpKind.ck.deps[0];
+                sources.add(new JavaSource(toRemove));
+            }
+            JavacTask ct = (JavacTask)tool.getTask(debugWriter, null, null,
+                    Arrays.asList("-d", classesDir.getAbsolutePath(), "-source", String.valueOf(cpKind.version)), null, sources);
+            try {
+                ct.generate();
+                if (toRemove != null) {
+                    debugWriter.append("Remove " + toRemove.name + ".class from" + classesDir.getAbsolutePath() + "\n");
+                    File fileToRemove = new File(classesDir, toRemove.name + ".class");
+                    fileToRemove.delete();
+                }
+            } catch (Throwable ex) {
+                throw new AssertionError("Error thrown when generating side-classes");
+            }
+        }
+
+        //step 3 - compile
+        debugWriter.append("Compiling test\n");
+        List<JavaSource> sourcefiles = new ArrayList<>();
+        for (ClassKind ck : sources) {
+            sourcefiles.add(new JavaSource(ck));
+        }
+        JavacTask ct = (JavacTask)tool.getTask(debugWriter, null, diagChecker,
+                    Arrays.asList("-XDdumpLambdaToMethodStats", "-d", outDir.getAbsolutePath(),
+                                  "-sourcepath", srcDir.getAbsolutePath(),
+                                  "-classpath", classesDir.getAbsolutePath(),
+                                  pp.preferOpt), null, sourcefiles);
+        try {
+            ct.generate();
+        } catch (Throwable ex) {
+            throw new AssertionError("Error thrown when compiling test case");
+        }
+        check();
+    }
+
+    void check() {
+        checkCount++;
+        if (diagChecker.errorFound) {
+            throw new AssertionError("Unexpected compilation failure");
+        }
+
+        boolean altMetafactory =
+                cpKind == ClasspathKind.B7 &&
+                !sources.contains(ClassKind.B) &&
+                (pp == PreferPolicy.NEWER || !spKind.sources.contains(ClassKind.B));
+
+        if (altMetafactory != diagChecker.altMetafactory) {
+            throw new AssertionError("Bad metafactory detected - expected altMetafactory: " + altMetafactory +
+                    "\ntest: " + testDir);
+        }
+    }
+
+    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+        boolean altMetafactory = false;
+        boolean errorFound = false;
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                errorFound = true;
+            } else if (statProcessor.matches(diagnostic)) {
+                statProcessor.process(diagnostic);
+            }
+        }
+
+        abstract class DiagnosticProcessor {
+
+            List<String> codes;
+            Diagnostic.Kind kind;
+
+            public DiagnosticProcessor(Kind kind, String... codes) {
+                this.codes = Arrays.asList(codes);
+                this.kind = kind;
+            }
+
+            abstract void process(Diagnostic<? extends JavaFileObject> diagnostic);
+
+            boolean matches(Diagnostic<? extends JavaFileObject> diagnostic) {
+                return (codes.isEmpty() || codes.contains(diagnostic.getCode())) &&
+                        diagnostic.getKind() == kind;
+            }
+
+            JCDiagnostic asJCDiagnostic(Diagnostic<? extends JavaFileObject> diagnostic) {
+                if (diagnostic instanceof JCDiagnostic) {
+                    return (JCDiagnostic)diagnostic;
+                } else if (diagnostic instanceof DiagnosticSourceUnwrapper) {
+                    return ((DiagnosticSourceUnwrapper)diagnostic).d;
+                } else {
+                    throw new AssertionError("Cannot convert diagnostic to JCDiagnostic: " + diagnostic.getClass().getName());
+                }
+            }
+        }
+
+        DiagnosticProcessor statProcessor = new DiagnosticProcessor(Kind.NOTE,
+                "compiler.note.lambda.stat",
+                "compiler.note.mref.stat",
+                "compiler.note.mref.stat.1") {
+            @Override
+            void process(Diagnostic<? extends JavaFileObject> diagnostic) {
+                JCDiagnostic diag = asJCDiagnostic(diagnostic);
+                if ((Boolean)diag.getArgs()[0]) {
+                    altMetafactory = true;
+                }
+            }
+        };
+    }
+}
--- a/langtools/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java	Thu Jul 11 14:07:39 2013 +0100
@@ -105,7 +105,7 @@
             Class returnType = m.getReturnType();
             assertTrue(types.remove(returnType.getName()));
         }
-        assertTrue(types.isEmpty());
+        assertTrue(types.size() == 1); //there's a bridge
     }
 
 
--- a/langtools/test/tools/javac/lambda/methodReference/BridgeMethod.java	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/test/tools/javac/lambda/methodReference/BridgeMethod.java	Thu Jul 11 14:07:39 2013 +0100
@@ -112,6 +112,6 @@
             Class<?> returnType = m.getReturnType();
             assertTrue(types.remove(returnType.getName()));
         }
-        assertTrue(types.isEmpty());
+        assertTrue(types.size() == 1); //there's a bridge
     }
 }
--- a/langtools/test/tools/javac/lambdaShapes/org/openjdk/tests/vm/DefaultMethodsTest.java	Thu Jul 11 10:13:57 2013 -0700
+++ b/langtools/test/tools/javac/lambdaShapes/org/openjdk/tests/vm/DefaultMethodsTest.java	Thu Jul 11 14:07:39 2013 +0100
@@ -395,6 +395,7 @@
      * TEST: C c = new C(); c.m() == 88;
      * TEST: I i = new C(); i.m() == 88;
      */
+    @Test(enabled=false)
     public void testSelfFill() {
         // This test ensures that a concrete method overrides a default method
         // that matches at the language-level, but has a different method
@@ -484,6 +485,7 @@
      * TEST: J<String,String> j = new C(); j.m("A","B","C") == 88;
      * TEST: K<String> k = new C(); k.m("A","B","C") == 88;
      */
+    @Test(enabled=false)
     public void testBridges() {
         DefaultMethod dm = new DefaultMethod("int", stdMethodName, "return 99;",
             new MethodParameter("T", "t"), new MethodParameter("V", "v"),
@@ -672,6 +674,7 @@
      * class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger;
      * TEST: S s = new S(); s.foo() == new Integer(99)
      */
+    @Test(enabled=false)
     public void testCovarBridge() {
         Interface I = new Interface("I", new DefaultMethod(
             "Integer", "m", "return new Integer(88);"));
@@ -754,6 +757,7 @@
      * Test that a erased-signature-matching method does not implement
      * non-language-level matching methods
      */
+    @Test(enabled=false)
     public void testNonConcreteFill() {
         AbstractMethod ipm = new AbstractMethod("int", "m",
             new MethodParameter("T", "t"),