OpenJDK / lambda / lambda / langtools
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; }