OpenJDK / lambda / lambda / langtools
changeset 1447:027ae5764025
Bug fixes:
*) LambdaToInnerClass translator should not emit non-static anonymous inner class if lambda is inside self-constructor call (using this(...)).
*) Routine for finding functional descriptor should return both the descriptor symbol (one of the method symbols in a given interface) and the instantiated descriptor type
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Tue Aug 07 15:55:05 2012 +0100 @@ -44,6 +44,7 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.BoundKind.*; import static com.sun.tools.javac.util.ListBuffer.lb; +import com.sun.xml.internal.messaging.saaj.packaging.mime.util.BEncoderStream; /** * Utility class containing various operations on types. @@ -335,18 +336,34 @@ return diagnostic; } } + + private class FunctionalDescriptorResult { + Symbol descSym; + + FunctionalDescriptorResult(Symbol descSym) { + this.descSym = descSym; + } + + public Symbol getSymbol() { + return descSym; + } + + public Type getType(Type origin) { + return memberType(origin, descSym); + } + } class DescriptorCache { private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>(); class Entry { - final MethodSymbol cachedDesc; + final FunctionalDescriptorResult cachedDescRes; final int prevMark; - public Entry(MethodSymbol cachedDesc, + public Entry(FunctionalDescriptorResult cachedDescRes, int prevMark) { - this.cachedDesc = cachedDesc; + this.cachedDescRes = cachedDescRes; this.prevMark = prevMark; } @@ -355,17 +372,17 @@ } } - MethodSymbol get(TypeSymbol origin) throws SAMConversionFailure { + FunctionalDescriptorResult get(TypeSymbol origin) throws SAMConversionFailure { Entry e = _map.get(origin); CompoundScope members = membersClosure(origin.type, false); if (e == null || !e.matches(members.getMark())) { - MethodSymbol desc = findDescriptorInternal(origin, members); - _map.put(origin, new Entry(desc, members.getMark())); - return desc; + FunctionalDescriptorResult descRes = findDescriptorInternal(origin, members); + _map.put(origin, new Entry(descRes, members.getMark())); + return descRes; } else { - return e.cachedDesc; + return e.cachedDescRes; } } @@ -391,29 +408,27 @@ } }; - public MethodSymbol findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws SAMConversionFailure { + public FunctionalDescriptorResult findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws SAMConversionFailure { if (!origin.isInterface()) { //t must be an abstract class or an interface throw samConversionFailure.setMessage("target.for.lambda.conv.must.be.interface"); } - ListBuffer<Symbol> abstracts = ListBuffer.lb(); - int count = 0; + final ListBuffer<Symbol> abstracts = ListBuffer.lb(); for (Symbol sym : membersCache.getElements(new DescriptorFilter(origin))) { - count++; Type mtype = memberType(origin.type, sym); if (abstracts.isEmpty() || (sym.name == abstracts.first().name && overrideEquivalent(mtype, memberType(origin.type, abstracts.first())))) { abstracts.append(sym); + } else { + //the target method(s) should be the only abstract members of t + throw samConversionFailure.setMessage("incompatible.targets.for.lambda.conv", Kinds.kindName(origin), origin); } } if (abstracts.isEmpty()) { //t must define a suitable non-generic method throw samConversionFailure.setMessage("no.target.method.for.lambda.conv", Kinds.kindName(origin), origin); - } else if (abstracts.size() != count) { - //the target method(s) should be the only abstract members of t - throw samConversionFailure.setMessage("incompatible.targets.for.lambda.conv", Kinds.kindName(origin), origin); } else if (abstracts.size() == 1) { if (abstracts.first().type.tag == FORALL) { throw samConversionFailure.setMessage("invalid.generic.target.for.lambda.conv", @@ -421,7 +436,7 @@ Kinds.kindName(origin), origin); } else { - return (MethodSymbol)abstracts.first(); + return new FunctionalDescriptorResult(abstracts.first()); } } else { // size > 1 for (Symbol msym : abstracts) { @@ -432,12 +447,12 @@ origin); } } - MethodType mtype = mergeDescriptors(origin, abstracts.toList()); - if (mtype == null) { + FunctionalDescriptorResult descRes = mergeDescriptors(origin, abstracts.toList()); + if (descRes == null) { //we can get here if the SAM class is ill-formed throw samConversionFailure.setMessage("incompatible.targets.for.lambda.conv", Kinds.kindName(origin), origin); } - return new MethodSymbol(abstracts.first().flags(), abstracts.first().name, mtype, origin); + return descRes; } } @@ -447,7 +462,7 @@ * type is a method type that is override-equivalent and return-type * substitutable with each method in the original list. */ - private MethodType mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) { + private FunctionalDescriptorResult mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) { //merge argument types - simply take the signature that is a //subsigature of all other signatures in the list (as per JLS 8.4.2) List<Symbol> mostSpecific = List.nil(); @@ -501,9 +516,15 @@ mt1.getThrownTypes() : chk.intersect(mt1.getThrownTypes(), thrown); } - - Type mt = memberType(origin.type, bestSoFar); - return new MethodType(mt.getParameterTypes(), mt.getReturnType(), thrown, syms.methodClass); + + final List<Type> thrown1 = thrown; + return new FunctionalDescriptorResult(bestSoFar) { + @Override + public Type getType(Type origin) { + Type mt = memberType(origin, getSymbol()); + return new MethodType(mt.getParameterTypes(), mt.getReturnType(), thrown1, syms.methodClass); + } + }; } boolean isSubtypeInternal(Type s, Type t) { @@ -518,26 +539,22 @@ /** * Find the method descriptor associated to this class symbol - if the * symbol 'origin' is not a functional interface, an exception is thrown. - * The returned descriptor is a method symbol whose owner is 'origin'. */ - public MethodSymbol findDescriptor(TypeSymbol origin) throws SAMConversionFailure { - return descCache.get(origin); + public Symbol findDescriptorSymbol(TypeSymbol origin) throws SAMConversionFailure { + return descCache.get(origin).getSymbol(); } - + /** - * Find the method descriptor associated to this class type - if the - * type 'site' is not a functional interface, an exception is thrown. - * The returned descriptor is a method type (an instantiated signature of - * the method descriptor symbol seen as a member of 'site'). + * Find the type of the method descriptor associated to this class symbol - + * if the symbol 'origin' is not a functional interface, an exception is thrown. */ - public MethodType findDescriptor(Type site) throws SAMConversionFailure { - MethodSymbol msym = findDescriptor(site.tsym); - return (MethodType)memberType(site, msym); + public Type findDescriptorType(Type origin) throws SAMConversionFailure { + return descCache.get(origin.tsym).getType(origin); } public boolean isSam(TypeSymbol tsym) { try { - findDescriptor(tsym); + findDescriptorSymbol(tsym); return true; } catch (SAMConversionFailure ex) { return false;
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Tue Aug 07 15:55:05 2012 +0100 @@ -2159,7 +2159,7 @@ clazztype.tag == CLASS && lambdaOrReferenceAllowed(tree) && types.isSam(clazztype.tsym)) { - MethodSymbol samDescriptor = types.findDescriptor(clazztype.tsym); + Symbol samDescriptor = types.findDescriptorSymbol(clazztype.tsym); int count = 0; boolean found = false; for (Symbol sym : csym.members().getElements()) { @@ -2254,7 +2254,7 @@ } Type target = infer.inferSAM(that, pt(), explicitParamTypes, resultInfo.checkContext); - Type lambdaType = types.findDescriptor(target); + Type lambdaType = types.findDescriptorType(target); if (!TreeInfo.isExplicitLambda(that)) { //add param type info in the AST @@ -2675,7 +2675,7 @@ } Type target = infer.inferSAM(that, pt(), null, resultInfo.checkContext); - Type desc = types.findDescriptor(target); + Type desc = types.findDescriptorType(target); //attrib type-arguments and receiver expr List<Type> typeargtypes = List.nil(); @@ -2794,7 +2794,7 @@ * SAM descriptor. */ void checkLambdaCompatible(JCLambda tree, Type target, CheckContext checkContext, boolean speculativeAttr) { - Type descriptor = types.findDescriptor(target); + Type descriptor = types.findDescriptorType(target); Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types); //return values have already been checked - but if lambda has no return @@ -2821,7 +2821,7 @@ } void checkReferenceCompatible(JCMemberReference tree, Type target, Type refType, CheckContext checkContext, boolean speculativeAttr) { - Type descriptor = types.findDescriptor(target); + Type descriptor = types.findDescriptorType(target); Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types); Type resType = tree.getMode() == ReferenceMode.INVOKE ?
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Tue Aug 07 15:55:05 2012 +0100 @@ -943,7 +943,7 @@ } void checkAccessibleSAM(DiagnosticPosition pos, Env<AttrContext> env, Type sam) { - Type desc = types.findDescriptor(sam); + Type desc = types.findDescriptorType(sam); SamAccessibilityChecker samAccessibilityChecker = new SamAccessibilityChecker(env); //check args accessibility (only if implicit parameter types)
--- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Tue Aug 07 15:55:05 2012 +0100 @@ -329,7 +329,7 @@ if (!types.isSam(pt.tsym)) { return; } - Type descType = types.findDescriptor(pt); + Type descType = types.findDescriptorType(pt); List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); if (!TreeInfo.isExplicitLambda(tree) && freeArgVars.nonEmpty()) { @@ -358,7 +358,7 @@ if (!types.isSam(pt.tsym)) { return; } - Type descType = types.findDescriptor(pt); + Type descType = types.findDescriptorType(pt); List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); stuckVars.addAll(freeArgVars); }
--- a/src/share/classes/com/sun/tools/javac/comp/GraphInfer.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/GraphInfer.java Tue Aug 07 15:55:05 2012 +0100 @@ -283,7 +283,7 @@ //get constraints from explicit params (this is done by //checking that explicit param types are equal to the ones //in the SAM descriptors) - List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes(); + List<Type> descParameterTypes = types.findDescriptorType(formalSam).getParameterTypes(); if (descParameterTypes.size() != paramTypes.size()) { checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); return types.createErrorType(samType); @@ -319,7 +319,7 @@ if (paramTypes == null) { try { //we need to fix synthetic inference variables in argument position - samInferenceContext.solve(samInferenceContext.freeVarsIn(types.findDescriptor(formalSam).getParameterTypes())); + samInferenceContext.solve(samInferenceContext.freeVarsIn(types.findDescriptorType(formalSam).getParameterTypes())); } catch (InferenceException ex) { checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); return types.createErrorType(samType);
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java Tue Aug 07 15:55:05 2012 +0100 @@ -549,7 +549,8 @@ super(tree); SuperCallAnalyzer sca = new SuperCallAnalyzer(); sca.scan(tree.body); - long flags = sca.captureSuper ? 0 : owner.flags() & STATIC; + long flags = isSelfCall ? STATIC : + (sca.captureSuper ? 0 : owner.flags() & STATIC); this.lambdaClassSym = makeFunctionalClassSym(flags, tree.targetType, owner); this.translatedSym = makeFunctionalDescriptorSym(tree.targetType, lambdaClassSym); } @@ -643,7 +644,8 @@ ReferenceToInnerTranslationContext(JCMemberReference tree) { super(tree); - this.referenceClassSym = makeFunctionalClassSym(owner.flags() & STATIC, tree.targetType, owner); + long flags = isSelfCall ? STATIC : (owner.flags() & STATIC); + this.referenceClassSym = makeFunctionalClassSym(flags, tree.targetType, owner); this.translatedSym = makeFunctionalDescriptorSym(tree.targetType, referenceClassSym); if (tree.hasKind(ReferenceKind.SUPER)) { this.bridgeSym = makeSyntheticMethod(0, "$bridge$" + tree.pos, types.erasure(translatedSym.type), instance());
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Aug 07 15:55:05 2012 +0100 @@ -510,7 +510,7 @@ //determine the static bsm args Type mtype = makeFunctionalDescriptorType(targetType, true); List<Object> staticArgs = List.<Object>of( - new Pool.MemberReference(ClassFile.REF_invokeInterface, types.findDescriptor(targetType.tsym)), + new Pool.MemberReference(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(targetType.tsym)), new Pool.MemberReference(refKind, refSym), new MethodType(mtype.getParameterTypes(), mtype.getReturnType(), @@ -722,7 +722,7 @@ } protected Type generatedLambdaSig() { - return types.erasure(types.findDescriptor(tree.targetType)); + return types.erasure(types.findDescriptorType(tree.targetType)); } } @@ -770,7 +770,7 @@ } protected Type bridgedRefSig() { - return types.erasure(types.findDescriptor(tree.targetType.tsym).type); + return types.erasure(types.findDescriptorSymbol(tree.targetType.tsym).type); } } }
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java Tue Aug 07 15:55:05 2012 +0100 @@ -303,7 +303,7 @@ // </editor-fold> private MethodSymbol makeSamDescriptor(Type targetType) { - return types.findDescriptor(targetType.tsym); + return (MethodSymbol)types.findDescriptorSymbol(targetType.tsym); } private Type makeFunctionalDescriptorType(Type targetType, MethodSymbol samDescriptor, boolean erased) { @@ -374,6 +374,9 @@ /** the frame stack - used to reconstruct translation info about enclosing scopes */ List<Frame> frameStack; + + /** are we inside a constructor call (i.e. 'this(xyz)') */ + protected boolean isSelfCall = false; abstract TranslationContext makeLambdaContext(JCLambda tree); @@ -648,6 +651,20 @@ frameStack = prevStack; } } + + @Override + public void visitApply(JCMethodInvocation tree) { + boolean prevSelfCall = false; + try { + if (tree.meth.hasTag(IDENT) && + ((JCIdent)tree.meth).name == names._this) { + isSelfCall = true; + } + super.visitApply(tree); + } finally { + isSelfCall = prevSelfCall; + } + } /** * This is used to filter out those identifiers that needs to be adjusted
--- a/src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java Tue Aug 07 15:55:05 2012 +0100 @@ -251,7 +251,7 @@ //get constraints from explicit params (this is done by //checking that explicit param types are equal to the ones //in the SAM descriptors) - List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes(); + List<Type> descParameterTypes = types.findDescriptorType(formalSam).getParameterTypes(); if (descParameterTypes.size() != paramTypes.size()) { checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); return types.createErrorType(samType);
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Aug 06 12:11:27 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Tue Aug 07 15:55:05 2012 +0100 @@ -1327,16 +1327,16 @@ //this is unexpectedas the method was deemed applicable Assert.error(); } - Type ret_s = types.findDescriptor(s).getReturnType(); - Type ret_t = types.findDescriptor(t).getReturnType(); + Type ret_s = types.findDescriptorType(s).getReturnType(); + Type ret_t = types.findDescriptorType(t).getReturnType(); //covariant most specific check for functional descriptor return type if (!types.isSubtype(ret_s, ret_t)) { return false; } - List<Type> args_s = types.findDescriptor(s).getParameterTypes(); - List<Type> args_t = types.findDescriptor(t).getParameterTypes(); + List<Type> args_s = types.findDescriptorType(s).getParameterTypes(); + List<Type> args_t = types.findDescriptorType(t).getParameterTypes(); //arity must be identical if (args_s.length() != args_t.length()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lambda/LambdaConv24.java Tue Aug 07 15:55:05 2012 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012, 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 + * @summary check that lambda inside 'this' call is handled properly + * @run main LambdaConv24 + */ +public class LambdaConv24 { + + static int assertionCount = 0; + + static void assertTrue(boolean cond) { + assertionCount++; + if (!cond) + throw new AssertionError(); + } + + interface SAM<X> { + boolean m(X x); + } + + LambdaConv24(SAM<String> p) { + assertTrue(p.m("42")); + } + + LambdaConv24(int i) { + this(s->true); + } + + LambdaConv24(int i1, int i2) { + this(LambdaConv24::m); + } + + static boolean m(String s) { return true; } + + public static void main(String[] args) { + new LambdaConv24(1); + new LambdaConv24(1,2); + assertTrue(assertionCount == 2); + } +}