changeset 2018:3015fd8397e9

Add type-based calculation for metafactory bridging
author mcimadamore
date Thu, 25 Apr 2013 12:40:07 +0100
parents 16dca72be9cf
children 10c9e12512a3
files src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/comp/TransTypes.java
diffstat 4 files changed, 98 insertions(+), 147 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Tue Apr 23 14:45:50 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Apr 25 12:40:07 2013 +0100
@@ -40,7 +40,9 @@
 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.Env;
 import com.sun.tools.javac.jvm.ClassReader;
 import com.sun.tools.javac.util.*;
 import static com.sun.tools.javac.code.BoundKind.*;
@@ -348,11 +350,9 @@
 
         class FunctionDescriptor {
             Symbol descSym;
-            List<Symbol> descOverrides;
 
             FunctionDescriptor(Symbol descSym, TypeSymbol origin) {
                 this.descSym = descSym;
-                descOverrides = descOverrides(origin);
             }
 
             public Symbol getSymbol() {
@@ -368,36 +368,6 @@
                 }
                 return memberType(site, descSym);
             }
-            
-            public List<Symbol> descOverrides(TypeSymbol origin) {
-                Symbol newDesc =
-                        new MethodSymbol(descSym.flags_field, descSym.name, memberType(origin.type, descSym), origin);
-                CompoundScope members = membersClosure(origin.type, false);
-                ListBuffer<Symbol> overridden = ListBuffer.lb();
-                outer: for (Symbol m2 : members.getElementsByName(newDesc.name, bridgeFilter)) {
-                    if (newDesc.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) &&
-                                    ((((ClassSymbol)m3.owner).sourcefile.getKind() == JavaFileObject.Kind.SOURCE) ||
-                                    (((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;
-                    }
-                };
         }
 
         class Entry {
@@ -582,15 +552,6 @@
     public Type findDescriptorType(Type origin) throws FunctionDescriptorLookupError {
         return descCache.get(origin.tsym).getType(origin);
     }
-    
-    /**
-     * 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> findDescriptorOverrides(TypeSymbol origin) throws FunctionDescriptorLookupError {
-        return descCache.get(origin).descOverrides;
-    }
 
     /**
      * Is given type a functional interface?
@@ -648,6 +609,65 @@
             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, Type funcExprType, long cflags) {
+        Assert.check(isFunctionalInterface(funcExprType));
+        Symbol descSym = findDescriptorSymbol(funcExprType.tsym);
+        Type descType = findDescriptorType(funcExprType);
+        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 = List.of(removeWildcards(funcExprType));
+        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) &&
+                            ((((ClassSymbol)m3.owner).sourcefile.getKind() == JavaFileObject.Kind.SOURCE) ||
+                            (((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;
+            }
+        };
     // </editor-fold>
 
    /**
@@ -2950,17 +2970,6 @@
      *  changing all recursive bounds from old to new list.
      */
     public List<Type> newInstances(List<Type> tvars) {
-        return newInstances(tvars, identityNewInstanceFun);
-    }
-    //where
-        private NewInstanceFun identityNewInstanceFun = new NewInstanceFun() {
-            @Override
-            public TypeSymbol tsym(TypeSymbol tsym, Type newType) {
-                return tsym;
-            }
-        };
-    
-    public List<Type> newInstances(List<Type> tvars, NewInstanceFun newInstanceFun) {
         List<Type> tvars1 = Type.map(tvars, newInstanceFun);
         for (List<Type> l = tvars1; l.nonEmpty(); l = l.tail) {
             TypeVar tv = (TypeVar) l.head;
@@ -2968,20 +2977,9 @@
         }
         return tvars1;
     }
-    
-    public static abstract class NewInstanceFun extends Mapping {
-        public NewInstanceFun() {
-            super("newInstanceFun");
-        }
-
-        public Type apply(Type t) {
-            TypeVar tv = new TypeVar(null, t.getUpperBound(), t.getLowerBound());
-            tv.tsym = tsym(t.tsym, t);
-            return tv;
-        }
-
-        public abstract TypeSymbol tsym(TypeSymbol tsym, Type newType);
-    }
+    private static final Mapping newInstanceFun = new Mapping("newInstanceFun") {
+            public Type apply(Type t) { return new TypeVar(t.tsym, t.getUpperBound(), t.getLowerBound()); }
+        };
     // </editor-fold>
 
     public Type createMethodTypeWithParameters(Type original, List<Type> newParams) {
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Apr 23 14:45:50 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Apr 25 12:40:07 2013 +0100
@@ -2277,7 +2277,6 @@
             if (pt() != Type.recoveryType) {
                 target = targetChecker.visit(target, that);
                 lambdaType = types.findDescriptorType(target);
-                chk.checkFunctionalInterface(that, target);
             } else {
                 target = Type.recoveryType;
                 lambdaType = fallbackDescriptorType(that);
@@ -2382,9 +2381,10 @@
             flow.analyzeLambda(env, that, make, isSpeculativeRound);
 
             checkLambdaCompatible(that, lambdaType, resultInfo.checkContext, isSpeculativeRound);
-
-            if (!isSpeculativeRound) {
+            
+            if (!isSpeculativeRound && target != Type.recoveryType) {
                 checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType, target);
+                checkFunctionalInterfaceClass(localEnv, resultInfo.checkContext.inferenceContext(), target);
             }
             result = check(that, target, VAL, resultInfo);
         } catch (Types.FunctionDescriptorLookupError ex) {
@@ -2486,6 +2486,22 @@
             }
         }
 
+        private void checkFunctionalInterfaceClass(final Env<AttrContext> env,
+                final InferenceContext inferenceContext, final Type funcExprType) {
+            if (inferenceContext.free(funcExprType)) {
+                inferenceContext.addFreeTypeListener(List.of(funcExprType), new FreeTypeListener() {
+                    @Override
+                    public void typesInferred(InferenceContext inferenceContext) {
+                        checkFunctionalInterfaceClass(env, inferenceContext, inferenceContext.asInstType(funcExprType));
+                    }
+                });
+            } else {
+                ClassSymbol csym =
+                        types.makeFunctionalInterfaceClass(env, names.empty, funcExprType, ABSTRACT);
+                chk.checkImplementations(env.tree, csym, csym);
+            }
+        }
+
         /**
          * Lambda/method reference have a special check context that ensures
          * that i.e. a lambda return type is compatible with the expected
@@ -2621,7 +2637,6 @@
             if (pt() != Type.recoveryType) {
                 target = targetChecker.visit(pt(), that);
                 desc = types.findDescriptorType(target);
-                chk.checkFunctionalInterface(that, target);
             } else {
                 target = Type.recoveryType;
                 desc = fallbackDescriptorType(that);
@@ -2765,8 +2780,9 @@
             boolean isSpeculativeRound =
                     resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
             checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound);
-            if (!isSpeculativeRound) {
+            if (!isSpeculativeRound && target != Type.recoveryType) {
                 checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, target);
+                checkFunctionalInterfaceClass(localEnv, resultInfo.checkContext.inferenceContext(), target);
             }
             result = check(that, target, VAL, resultInfo);
         } catch (Types.FunctionDescriptorLookupError ex) {
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Apr 23 14:45:50 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Apr 25 12:40:07 2013 +0100
@@ -2287,24 +2287,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/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Apr 23 14:45:50 2013 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Thu Apr 25 12:40:07 2013 +0100
@@ -565,8 +565,8 @@
             currentMethod = null;
             tree.params = translate(tree.params);
             tree.body = translate(tree.body, null);
+            bridgeFunctionalInfoIfNeeded(tree);
             tree.type = erasure(tree.type);
-            bridgeFunctionalInfoIfNeeded(tree);
             result = tree;
         }
         finally {
@@ -581,55 +581,23 @@
      * bridges.
      */
     private void bridgeFunctionalInfoIfNeeded(JCTree.JCFunctionalExpression funcExpr) {
+        ClassSymbol csym = types.makeFunctionalInterfaceClass(env, syntheticBridgedInterfaceName(),
+                funcExpr.type, INTERFACE | ABSTRACT);
         if (!allowInterfaceBridges ||
-                types.findDescriptorOverrides(funcExpr.targets.head).length() <= 1) return;
-        //create synthetic interface symbol
-        long cflags = INTERFACE | ABSTRACT;
-        ClassSymbol csym = new ClassSymbol(cflags, syntheticBridgedInterfaceName(),
-                env.enclClass.sym.outermostClass());
-        //compute new type arguments
-        List<Type> formalTypeParameters = List.nil();
-        for (TypeSymbol tsym : funcExpr.targets) {
-            formalTypeParameters =
-                    formalTypeParameters.appendList(tsym.type.getTypeArguments());
-        }
-        List<Type> newTypeParameters = types.newInstances(formalTypeParameters,
-                new NewOwnerInstanceFun(csym));
-        Type.ClassType ctype = new Type.ClassType(Type.noType, newTypeParameters, csym);
-        ListBuffer<Type> newInterfaces = ListBuffer.lb();
-        for (TypeSymbol tsym : funcExpr.targets) {
-            newInterfaces.append(types.subst(tsym.type, formalTypeParameters, newTypeParameters));
+                types.functionalInterfaceBridges(csym).length() <= 1) return;
+        //append extra targets
+        for (TypeSymbol target : funcExpr.targets.tail) {
+            ((Type.ClassType)csym.type).interfaces_field =
+                    ((Type.ClassType)csym.type).interfaces_field.prepend(target.erasure(types));
         }
-        //compute supertypes
-        ctype.supertype_field = syms.objectType;
-        ctype.interfaces_field = newInterfaces.toList();
-        csym.type = ctype;
-        //fill in scope
-        csym.members_field = new Scope(csym);
-        MethodSymbol funcDescSym = (MethodSymbol)types.findDescriptorSymbol(funcExpr.targets.head);
-        final MethodSymbol newDescSym = new MethodSymbol(funcDescSym.flags(), funcDescSym.name, null, csym);
-        Type newDescType = types.subst(types.memberType(funcExpr.targets.head.type, funcDescSym),
-                formalTypeParameters, newTypeParameters);
-        if (funcExpr.descriptorType.hasTag(FORALL)) {
-            ForAll fa = (ForAll)funcExpr.descriptorType;
-            List<Type> newMethodTypeParameters =
-                    types.newInstances(fa.tvars, new NewOwnerInstanceFun(newDescSym));
-            newDescType = new Type.ForAll(newMethodTypeParameters,
-                    types.subst(newDescType.asMethodType(), fa.tvars, newMethodTypeParameters));
-        }
-        newDescSym.type = newDescType;
-        csym.members_field.enter(newDescSym);
-        //finish up symbol
-        csym.sourcefile = env.enclClass.sym.outermostClass().sourcefile;
-        csym.completer = null;
         //create an interface def
-        JCClassDecl idecl = make.ClassDef(make.Modifiers(cflags),
-                csym.name, make.TypeParams(newTypeParameters), null,
-                make.Types(types.interfaces(csym.type)), null);
+        JCClassDecl idecl = make.ClassDef(make.Modifiers(csym.flags()),
+                csym.name, List.<JCTypeParameter>nil(), null, make.Types(types.interfaces(csym.type)),
+                null);
         idecl.sym = csym;
         idecl.type = csym.type;
         //create method def
-        JCMethodDecl imeth = make.MethodDef(newDescSym, null);
+        JCMethodDecl imeth = make.MethodDef((MethodSymbol)types.findDescriptorSymbol(csym), null);
         idecl.defs = List.<JCTree>of(imeth);
         //compute bridges and analyze results
         translateClass(idecl);
@@ -642,19 +610,6 @@
         funcExpr.type = csym.type;
     }
     //where
-        private class NewOwnerInstanceFun extends Types.NewInstanceFun {
-            Symbol newOwner;
-
-            NewOwnerInstanceFun(Symbol newOwner) {
-                this.newOwner = newOwner;
-            }
-
-            @Override
-            public TypeSymbol tsym(TypeSymbol tsym, Type newType) {
-                return new TypeSymbol(0, tsym.name, newType, newOwner);
-            }
-        }
-
         private Name syntheticBridgedInterfaceName() {
             return names.fromString("I$" + bridgedFunctionalInterfaces.length());
         }
@@ -894,8 +849,8 @@
 
     public void visitReference(JCMemberReference tree) {
         tree.expr = translate(tree.expr, null);
+        bridgeFunctionalInfoIfNeeded(tree);
         tree.type = erasure(tree.type);
-        bridgeFunctionalInfoIfNeeded(tree);
         result = tree;
     }