# HG changeset patch # User rfield # Date 1360982438 28800 # Node ID 7cf27559c8df0c10593087d158edb685e6478397 # Parent 05b5bf59c9d3e67e448e33bf7b74b80d9653b01c 8004969: Generate $deserializeLambda$ method 8006763: super in method reference used in anonymous class - ClassFormatError is produced 8005632: Inner classes within lambdas cause build failures 8005653: Lambdas containing inner classes referencing external type variables do not correctly parameterize the inner classes Reviewed-by: mcimadamore diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Fri Feb 15 11:26:11 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Fri Feb 15 18:40:38 2013 -0800 @@ -126,6 +126,7 @@ public final Type stringBuilderType; public final Type cloneableType; public final Type serializableType; + public final Type serializedLambdaType; public final Type methodHandleType; public final Type methodHandleLookupType; public final Type methodTypeType; @@ -458,6 +459,7 @@ cloneableType = enterClass("java.lang.Cloneable"); throwableType = enterClass("java.lang.Throwable"); serializableType = enterClass("java.io.Serializable"); + serializedLambdaType = enterClass("java.lang.invoke.SerializedLambda"); methodHandleType = enterClass("java.lang.invoke.MethodHandle"); methodHandleLookupType = enterClass("java.lang.invoke.MethodHandles$Lookup"); methodTypeType = enterClass("java.lang.invoke.MethodType"); @@ -514,6 +516,7 @@ synthesizeEmptyInterfaceIfMissing(cloneableType); synthesizeEmptyInterfaceIfMissing(serializableType); synthesizeEmptyInterfaceIfMissing(lambdaMetafactory); + synthesizeEmptyInterfaceIfMissing(serializedLambdaType); synthesizeBoxTypeIfMissing(doubleType); synthesizeBoxTypeIfMissing(floatType); synthesizeBoxTypeIfMissing(voidType); diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/code/Types.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Fri Feb 15 11:26:11 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Fri Feb 15 18:40:38 2013 -0800 @@ -48,6 +48,7 @@ import static com.sun.tools.javac.code.Symbol.*; import static com.sun.tools.javac.code.Type.*; import static com.sun.tools.javac.code.TypeTag.*; +import static com.sun.tools.javac.jvm.ClassFile.externalize; import static com.sun.tools.javac.util.ListBuffer.lb; /** @@ -4354,4 +4355,172 @@ return vis; } // + + // + + public static abstract class SignatureGenerator { + + private final Types types; + + protected abstract void append(char ch); + protected abstract void append(byte[] ba); + protected abstract void append(Name name); + protected void classReference(ClassSymbol c) { /* by default: no-op */ } + + protected SignatureGenerator(Types types) { + this.types = types; + } + + /** + * Assemble signature of given type in string buffer. + */ + public void assembleSig(Type type) { + type = type.unannotatedType(); + switch (type.getTag()) { + case BYTE: + append('B'); + break; + case SHORT: + append('S'); + break; + case CHAR: + append('C'); + break; + case INT: + append('I'); + break; + case LONG: + append('J'); + break; + case FLOAT: + append('F'); + break; + case DOUBLE: + append('D'); + break; + case BOOLEAN: + append('Z'); + break; + case VOID: + append('V'); + break; + case CLASS: + append('L'); + assembleClassSig(type); + append(';'); + break; + case ARRAY: + ArrayType at = (ArrayType) type; + append('['); + assembleSig(at.elemtype); + break; + case METHOD: + MethodType mt = (MethodType) type; + append('('); + assembleSig(mt.argtypes); + append(')'); + assembleSig(mt.restype); + if (hasTypeVar(mt.thrown)) { + for (List l = mt.thrown; l.nonEmpty(); l = l.tail) { + append('^'); + assembleSig(l.head); + } + } + break; + case WILDCARD: { + Type.WildcardType ta = (Type.WildcardType) type; + switch (ta.kind) { + case SUPER: + append('-'); + assembleSig(ta.type); + break; + case EXTENDS: + append('+'); + assembleSig(ta.type); + break; + case UNBOUND: + append('*'); + break; + default: + throw new AssertionError(ta.kind); + } + break; + } + case TYPEVAR: + append('T'); + append(type.tsym.name); + append(';'); + break; + case FORALL: + Type.ForAll ft = (Type.ForAll) type; + assembleParamsSig(ft.tvars); + assembleSig(ft.qtype); + break; + default: + throw new AssertionError("typeSig " + type.getTag()); + } + } + + public boolean hasTypeVar(List l) { + while (l.nonEmpty()) { + if (l.head.hasTag(TypeTag.TYPEVAR)) { + return true; + } + l = l.tail; + } + return false; + } + + public void assembleClassSig(Type type) { + type = type.unannotatedType(); + ClassType ct = (ClassType) type; + ClassSymbol c = (ClassSymbol) ct.tsym; + classReference(c); + Type outer = ct.getEnclosingType(); + if (outer.allparams().nonEmpty()) { + boolean rawOuter = + c.owner.kind == Kinds.MTH || // either a local class + c.name == types.names.empty; // or anonymous + assembleClassSig(rawOuter + ? types.erasure(outer) + : outer); + append('.'); + Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname)); + append(rawOuter + ? c.flatname.subName(c.owner.enclClass().flatname.getByteLength() + 1, c.flatname.getByteLength()) + : c.name); + } else { + append(externalize(c.flatname)); + } + if (ct.getTypeArguments().nonEmpty()) { + append('<'); + assembleSig(ct.getTypeArguments()); + append('>'); + } + } + + public void assembleParamsSig(List typarams) { + append('<'); + for (List ts = typarams; ts.nonEmpty(); ts = ts.tail) { + Type.TypeVar tvar = (Type.TypeVar) ts.head; + append(tvar.tsym.name); + List bounds = types.getBounds(tvar); + if ((bounds.head.tsym.flags() & INTERFACE) != 0) { + append(':'); + } + for (List l = bounds; l.nonEmpty(); l = l.tail) { + append(':'); + assembleSig(l.head); + } + } + append('>'); + } + + private void assembleSig(List types) { + for (List ts = types; ts.nonEmpty(); ts = ts.tail) { + assembleSig(ts.head); + } + } + } + // } diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Feb 15 11:26:11 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Feb 15 18:40:38 2013 -0800 @@ -31,8 +31,8 @@ import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.tree.TreeTranslator; -import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.Scope; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; @@ -57,9 +57,7 @@ import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; -import static com.sun.tools.javac.code.TypeTag.BOT; -import static com.sun.tools.javac.code.TypeTag.NONE; -import static com.sun.tools.javac.code.TypeTag.VOID; +import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; /** @@ -89,9 +87,51 @@ /** current translation context (visitor argument) */ private TranslationContext context; - /** list of translated methods - **/ - private ListBuffer translatedMethodList; + /** info about the current class being processed */ + private KlassInfo kInfo; + + /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ + public static final int FLAG_SERIALIZABLE = 1 << 0; + + /** Flag for alternate metafactories indicating the lambda object has multiple targets */ + public static final int FLAG_MARKERS = 1 << 1; + + private class KlassInfo { + + /** + * list of methods to append + */ + private ListBuffer appendedMethodList; + + /** + * list of deserialization cases + */ + private final Map> deserializeCases; + + /** + * deserialize method symbol + */ + private final MethodSymbol deserMethodSym; + + /** + * deserialize method parameter symbol + */ + private final VarSymbol deserParamSym; + + private KlassInfo(Symbol kSym) { + appendedMethodList = ListBuffer.lb(); + deserializeCases = new HashMap>(); + long flags = PRIVATE | STATIC | SYNTHETIC; + MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, + List.nil(), syms.methodClass); + deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym); + deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), syms.serializedLambdaType, deserMethodSym); + } + + private void addMethod(JCTree decl) { + appendedMethodList = appendedMethodList.prepend(decl); + } + } // private static final Context.Key unlambdaKey = @@ -112,11 +152,7 @@ make = TreeMaker.instance(context); types = Types.instance(context); transTypes = TransTypes.instance(context); - this.analyzer = makeAnalyzer(); - } - - private LambdaAnalyzer makeAnalyzer() { - return new LambdaAnalyzer(); + analyzer = new LambdaAnalyzer(); } // @@ -168,18 +204,22 @@ //analyze class analyzer.analyzeClass(tree); } - ListBuffer prevTranslated = translatedMethodList; + KlassInfo prevKlassInfo = kInfo; try { - translatedMethodList = ListBuffer.lb(); + kInfo = new KlassInfo(tree.sym); super.visitClassDef(tree); + if (!kInfo.deserializeCases.isEmpty()) { + kInfo.addMethod(makeDeserializeMethod(tree.sym)); + } //add all translated instance methods here - tree.defs = tree.defs.appendList(translatedMethodList.toList()); - for (JCTree lambda : translatedMethodList) { + List newMethods = kInfo.appendedMethodList.toList(); + tree.defs = tree.defs.appendList(newMethods); + for (JCTree lambda : newMethods) { tree.sym.members().enter(((JCMethodDecl)lambda).sym); } result = tree; } finally { - translatedMethodList = prevTranslated; + kInfo = prevKlassInfo; } } @@ -217,7 +257,7 @@ lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); //Add the method to the list of methods to be added to this class. - translatedMethodList = translatedMethodList.prepend(lambdaDecl); + kInfo.addMethod(lambdaDecl); //now that we have generated a method for the lambda expression, //we can translate the lambda into a method reference pointing to the newly @@ -234,7 +274,7 @@ if (!sym.isStatic()) { syntheticInits.append(makeThis( - sym.owner.asType(), + sym.owner.enclClass().asType(), localContext.owner.enclClass())); } @@ -253,7 +293,7 @@ int refKind = referenceKind(sym); //convert to an invokedynamic call - result = makeMetaFactoryIndyCall(tree, refKind, sym, indy_args); + result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args); } private JCIdent makeThis(Type type, Symbol owner) { @@ -291,8 +331,8 @@ case IMPLICIT_INNER: /** Inner :: new */ case SUPER: /** super :: instMethod */ init = makeThis( - localContext.owner.owner.asType(), - localContext.owner); + localContext.owner.enclClass().asType(), + localContext.owner.enclClass()); break; case BOUND: /** Expr :: instMethod */ @@ -314,7 +354,7 @@ //build a sam instance using an indy call to the meta-factory - result = makeMetaFactoryIndyCall(tree, localContext.referenceKind(), refSym, indy_args); + result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args); } /** @@ -333,6 +373,9 @@ } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym); result = make.Ident(translatedSym).setType(tree.type); + } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) { + Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym); + result = make.Ident(translatedSym).setType(translatedSym.type); } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) { Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym); result = make.Ident(translatedSym).setType(tree.type); @@ -362,6 +405,16 @@ if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { JCExpression init = translate(tree.init); result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init); + } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) { + JCExpression init = translate(tree.init); + VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym); + result = make.VarDef(xsym, init); + // Replace the entered symbol for this variable + Scope sc = tree.sym.owner.members(); + if (sc != null) { + sc.remove(tree.sym); + sc.enter(xsym); + } } else { super.visitVarDef(tree); } @@ -451,6 +504,135 @@ return trans_block; } + private JCMethodDecl makeDeserializeMethod(Symbol kSym) { + ListBuffer cases = ListBuffer.lb(); + ListBuffer breaks = ListBuffer.lb(); + for (Map.Entry> entry : kInfo.deserializeCases.entrySet()) { + JCBreak br = make.Break(null); + breaks.add(br); + List stmts = entry.getValue().append(br).toList(); + cases.add(make.Case(make.Literal(entry.getKey()), stmts)); + } + JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList()); + for (JCBreak br : breaks) { + br.target = sw; + } + JCBlock body = make.Block(0L, List.of( + sw, + make.Throw(makeNewClass( + syms.illegalArgumentExceptionType, + List.of(make.Literal("Invalid lambda deserialization")))))); + JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()), + names.deserializeLambda, + make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym), + List.nil(), + List.of(make.VarDef(kInfo.deserParamSym, null)), + List.nil(), + body, + null); + deser.sym = kInfo.deserMethodSym; + deser.type = kInfo.deserMethodSym.type; + //System.err.printf("DESER: '%s'\n", deser); + return deser; + } + + /** Make an attributed class instance creation expression. + * @param ctype The class type. + * @param args The constructor arguments. + */ + JCNewClass makeNewClass(Type ctype, List args) { + JCNewClass tree = make.NewClass(null, + null, make.QualIdent(ctype.tsym), args, null); + tree.constructor = rs.resolveConstructor( + null, attrEnv, ctype, TreeInfo.types(args), List.nil()); + tree.type = ctype; + return tree; + } + + private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, + DiagnosticPosition pos, List staticArgs, MethodType indyType) { + String functionalInterfaceClass = classSig(targetType); + String functionalInterfaceMethodName = samSym.getSimpleName().toString(); + String functionalInterfaceMethodSignature = methodSig(types.erasure(samSym.type)); + String implClass = classSig(refSym.owner.type); + String implMethodName = refSym.getQualifiedName().toString(); + String implMethodSignature = methodSig(types.erasure(refSym.type)); + + JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind)); + ListBuffer serArgs = ListBuffer.lb(); + int i = 0; + for (Type t : indyType.getParameterTypes()) { + List indexAsArg = ListBuffer.lb().append(make.Literal(i)).toList(); + List argTypes = ListBuffer.lb().append(syms.intType).toList(); + serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg))); + ++i; + } + JCStatement stmt = make.If( + deserTest(deserTest(deserTest(deserTest(deserTest( + kindTest, + "getFunctionalInterfaceClass", functionalInterfaceClass), + "getFunctionalInterfaceMethodName", functionalInterfaceMethodName), + "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), + "getImplClass", implClass), + "getImplMethodSignature", implMethodSignature), + make.Return(makeIndyCall( + pos, + syms.lambdaMetafactory, + names.altMetaFactory, + staticArgs, indyType, serArgs.toList())), + null); + ListBuffer stmts = kInfo.deserializeCases.get(implMethodName); + if (stmts == null) { + stmts = ListBuffer.lb(); + kInfo.deserializeCases.put(implMethodName, stmts); + } + /**** + System.err.printf("+++++++++++++++++\n"); + System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass); + System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName); + System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature); + System.err.printf("*implMethodKind: %d\n", implMethodKind); + System.err.printf("*implClass: '%s'\n", implClass); + System.err.printf("*implMethodName: '%s'\n", implMethodName); + System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature); + ****/ + stmts.append(stmt); + } + + private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) { + JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2); + testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType); + testExpr.setType(syms.booleanType); + return testExpr; + } + + private JCExpression deserTest(JCExpression prev, String func, String lit) { + MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.nil(), syms.methodClass); + Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.nil()); + JCMethodInvocation eqtest = make.Apply( + List.nil(), + make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt), + List.of(make.Literal(lit))); + eqtest.setType(syms.booleanType); + JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest); + compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType); + compound.setType(syms.booleanType); + return compound; + } + + private JCExpression deserGetter(String func, Type type) { + return deserGetter(func, type, List.nil(), List.nil()); + } + + private JCExpression deserGetter(String func, Type type, List argTypes, List args) { + MethodType getmt = new MethodType(argTypes, type, List.nil(), syms.methodClass); + Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.nil()); + return make.Apply( + List.nil(), + make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt), + args).setType(type); + } + /** * Create new synthetic method with given flags, name, type, owner */ @@ -678,14 +860,14 @@ * * super is used */ private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) { - JCMethodDecl bridgeDecl = (new MemberReferenceBridger(tree, localContext).bridge()); - translatedMethodList = translatedMethodList.prepend(bridgeDecl); + kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge()); } /** * Generate an indy method call to the meta factory */ - private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, int refKind, Symbol refSym, List indy_args) { + private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory, + boolean isSerializable, int refKind, Symbol refSym, List indy_args) { //determine the static bsm args Type mtype = types.erasure(tree.descriptorType); MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); @@ -709,7 +891,31 @@ List.nil(), syms.methodClass); - return makeIndyCall(tree, syms.lambdaMetafactory, names.metaFactory, staticArgs, indyType, indy_args); + Name metafactoryName = needsAltMetafactory ? + names.altMetaFactory : names.metaFactory; + + if (needsAltMetafactory) { + ListBuffer markers = ListBuffer.lb(); + for (Symbol t : tree.targets.tail) { + if (t != syms.serializableType.tsym) { + markers.append(t); + } + } + int flags = isSerializable? FLAG_SERIALIZABLE : 0; + boolean hasMarkers = markers.nonEmpty(); + flags |= hasMarkers ? FLAG_MARKERS : 0; + staticArgs = staticArgs.append(flags); + if (hasMarkers) { + staticArgs = staticArgs.append(markers.length()); + staticArgs = staticArgs.appendList(markers.toList()); + } + if (isSerializable) { + addDeserializationCase(refKind, refSym, tree.type, samSym, + tree, staticArgs, indyType); + } + } + + return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args); } /** @@ -795,6 +1001,7 @@ } } } + // // \ @@ -814,6 +1021,20 @@ */ private int lambdaCount = 0; + /** + * keep the count of lambda expression defined in given context (used to + * generate unambiguous names for serializable lambdas) + */ + private Map serializableLambdaCounts = + new HashMap(); + + /** + * maps for fake clinit symbols to be used as owners of lambda occurring in + * a static var init context + */ + private Map clinits = + new HashMap(); + private void analyzeClass(JCClassDecl tree) { frameStack = List.nil(); scan(tree); @@ -836,21 +1057,26 @@ @Override public void visitClassDef(JCClassDecl tree) { List prevStack = frameStack; + Map prevSerializableLambdaCount = serializableLambdaCounts; + Map prevClinits = clinits; try { - if (frameStack.nonEmpty() && enclosingLambda() != null) { + serializableLambdaCounts = new HashMap(); + prevClinits = new HashMap(); + if (directlyEnclosingLambda() != null) { tree.sym.owner = owner(); - LambdaTranslationContext lambdaContext = (LambdaTranslationContext)contextMap.get(enclosingLambda()); + LambdaTranslationContext lambdaContext = (LambdaTranslationContext) contextMap.get(directlyEnclosingLambda()); Type encl = lambdaContext.enclosingType(); if (encl.hasTag(NONE)) { //if the translated lambda body occurs in a static context, //any class declaration within it must be made static + //@@@TODO: What about nested classes within lambda? tree.sym.flags_field |= STATIC; - ((ClassType)tree.sym.type).setEnclosingType(Type.noType); + ((ClassType) tree.sym.type).setEnclosingType(Type.noType); } else { //if the translated lambda body is in an instance context //the enclosing type of any class declaration within it //must be updated to point to the new enclosing type (if any) - ((ClassType)tree.sym.type).setEnclosingType(encl); + ((ClassType) tree.sym.type).setEnclosingType(encl); } } frameStack = frameStack.prepend(new Frame(tree)); @@ -858,8 +1084,10 @@ } finally { frameStack = prevStack; + serializableLambdaCounts = prevSerializableLambdaCount; + clinits = prevClinits; } - if (!tree.sym.isStatic() && frameStack.nonEmpty() && enclosingLambda() != null) { + if (!tree.sym.isStatic() && directlyEnclosingLambda() != null) { // Any (non-static) class defined within a lambda is an implicit 'this' reference // because its constructor will reference the enclosing class ((LambdaTranslationContext) context()).addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); @@ -868,9 +1096,7 @@ @Override public void visitIdent(JCIdent tree) { - if (context() == null || !lambdaIdentSymbolFilter(tree.sym)) { - super.visitIdent(tree); - } else { + if (context() != null && lambdaIdentSymbolFilter(tree.sym)) { if (tree.sym.kind == VAR && tree.sym.owner.kind == MTH && tree.type.constValue() == null) { @@ -902,6 +1128,7 @@ } } } + super.visitIdent(tree); } @Override @@ -969,9 +1196,22 @@ @Override public void visitVarDef(JCVariableDecl tree) { - if (frameStack.head.tree.hasTag(LAMBDA)) { - ((LambdaTranslationContext)context()).addSymbol(tree.sym, LOCAL_VAR); + TranslationContext context = context(); + LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)? + (LambdaTranslationContext)context : + null; + if (ltc != null) { + if (frameStack.head.tree.hasTag(LAMBDA)) { + ltc.addSymbol(tree.sym, LOCAL_VAR); + } + // Check for type variables (including as type arguments). + // If they occur within class nested in a lambda, mark for erasure + Type type = tree.sym.asType(); + if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) { + ltc.addSymbol(tree.sym, TYPE_VAR); + } } + List prevStack = frameStack; try { if (tree.sym.owner.kind == MTH) { @@ -986,7 +1226,25 @@ } private Name lambdaName() { - return names.lambda.append(names.fromString("$" + lambdaCount++)); + return names.lambda.append(names.fromString("" + lambdaCount++)); + } + + private Name serializedLambdaName(Symbol owner) { + StringBuilder buf = new StringBuilder(); + buf.append(names.lambda); + buf.append(owner.name); + buf.append('$'); + int methTypeHash = methodSig(owner.type).hashCode(); + buf.append(methTypeHash); + buf.append('$'); + String temp = buf.toString(); + Integer count = serializableLambdaCounts.get(temp); + if (count == null) { + count = 0; + } + buf.append(count++); + serializableLambdaCounts.put(temp, count); + return names.fromString(buf.toString()); } /** @@ -1008,10 +1266,12 @@ break; } JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree; - return makeSyntheticMethod(((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC, names.empty, null, cdecl.sym); + return initSym(cdecl.sym, + ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC); case BLOCK: JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree; - return makeSyntheticMethod(((JCBlock)frameStack2.head.tree).flags & STATIC | Flags.BLOCK, names.empty, null, cdecl2.sym); + return initSym(cdecl2.sym, + ((JCBlock)frameStack2.head.tree).flags & STATIC); case CLASSDEF: return ((JCClassDecl)frameStack2.head.tree).sym; case METHODDEF: @@ -1027,7 +1287,33 @@ return null; } - private JCTree enclosingLambda() { + private Symbol initSym(ClassSymbol csym, long flags) { + boolean isStatic = (flags & STATIC) != 0; + if (isStatic) { + //static clinits are generated in Gen - so we need to fake them + Symbol clinit = clinits.get(csym); + if (clinit == null) { + clinit = makeSyntheticMethod(STATIC, + names.clinit, + new MethodType(List.nil(), syms.voidType, List.nil(), syms.methodClass), + csym); + clinits.put(csym, clinit); + } + return clinit; + } else { + //get the first constructor and treat it as the instance init sym + for (Symbol s : csym.members_field.getElementsByName(names.init)) { + return s; + } + } + Assert.error("init not found"); + return null; + } + + private JCTree directlyEnclosingLambda() { + if (frameStack.isEmpty()) { + return null; + } List frameStack2 = frameStack; while (frameStack2.nonEmpty()) { switch (frameStack2.head.tree.getTag()) { @@ -1044,6 +1330,28 @@ return null; } + private boolean inClassWithinLambda() { + if (frameStack.isEmpty()) { + return false; + } + List frameStack2 = frameStack; + boolean classFound = false; + while (frameStack2.nonEmpty()) { + switch (frameStack2.head.tree.getTag()) { + case LAMBDA: + return classFound; + case CLASSDEF: + classFound = true; + frameStack2 = frameStack2.tail; + break; + default: + frameStack2 = frameStack2.tail; + } + } + // No lambda + return false; + } + /** * Return the declaration corresponding to a symbol in the enclosing * scope; the depth parameter is used to filter out symbols defined @@ -1178,6 +1486,22 @@ this.depth = frameStack.size() - 1; this.prev = context(); } + + /** does this functional expression need to be created using alternate metafactory? */ + boolean needsAltMetafactory() { + return (tree.targets.length() > 1 || + isSerializable()); + } + + /** does this functional expression require serialization support? */ + boolean isSerializable() { + for (Symbol target : tree.targets) { + if (types.asSuper(target.type, syms.serializableType.tsym) != null) { + return true; + } + } + return false; + } } /** @@ -1203,6 +1527,9 @@ /** map from class symbols to translated synthetic parameters (for captured member access) */ Map capturedThis = new LinkedHashMap(); + /** map from original to translated lambda locals */ + Map typeVars = new LinkedHashMap(); + /** the synthetic symbol for the method hoisting the translated lambda */ Symbol translatedSym; @@ -1214,7 +1541,8 @@ if (frame.tree.hasTag(VARDEF)) { self = ((JCVariableDecl)frame.tree).sym; } - this.translatedSym = makeSyntheticMethod(0, lambdaName(), null, owner.enclClass()); + Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName(); + this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass()); } /** @@ -1222,10 +1550,14 @@ * synthetic lambda body */ Symbol translate(String name, Symbol sym, LambdaSymbolKind skind) { - if (skind == CAPTURED_THIS) { - return sym; // self represented - } else { - return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); + switch (skind) { + case CAPTURED_THIS: + return sym; // self represented + case TYPE_VAR: + // Just erase the type var + return new VarSymbol(sym.flags(), names.fromString(name), types.erasure(sym.type), sym.owner); + default: + return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); } } @@ -1249,6 +1581,10 @@ transMap = lambdaParams; preferredName = sym.name.toString(); break; + case TYPE_VAR: + transMap = typeVars; + preferredName = sym.name.toString(); + break; default: throw new AssertionError(); } if (!transMap.containsKey(sym)) { @@ -1272,6 +1608,9 @@ case PARAM: translationMap.putAll(lambdaParams); break; + case TYPE_VAR: + translationMap.putAll(typeVars); + break; default: throw new AssertionError(); } } @@ -1311,8 +1650,8 @@ syntheticParams = params.toList(); //prepend synthetic args to translated lambda method signature - translatedSym.type = (MethodType) types.createMethodTypeWithParameters( - (MethodType) generatedLambdaSig(), + translatedSym.type = types.createMethodTypeWithParameters( + generatedLambdaSig(), TreeInfo.types(syntheticParams)); } @@ -1389,6 +1728,60 @@ CAPTURED_VAR, CAPTURED_THIS, LOCAL_VAR, - PARAM; + PARAM, + TYPE_VAR; + } + + /** + * **************************************************************** + * Signature Generation + * **************************************************************** + */ + + private String methodSig(Type type) { + L2MSignatureGenerator sg = new L2MSignatureGenerator(); + sg.assembleSig(type); + return sg.toString(); + } + + private String classSig(Type type) { + L2MSignatureGenerator sg = new L2MSignatureGenerator(); + sg.assembleClassSig(type); + return sg.toString(); + } + + /** + * Signature Generation + */ + private class L2MSignatureGenerator extends Types.SignatureGenerator { + + /** + * An output buffer for type signatures. + */ + StringBuilder sb = new StringBuilder(); + + L2MSignatureGenerator() { + super(types); + } + + @Override + protected void append(char ch) { + sb.append(ch); + } + + @Override + protected void append(byte[] ba) { + sb.append(new String(ba)); + } + + @Override + protected void append(Name name) { + sb.append(name.toString()); + } + + @Override + public String toString() { + return sb.toString(); + } } } diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Feb 15 11:26:11 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Feb 15 18:40:38 2013 -0800 @@ -309,7 +309,9 @@ /** Add member to class unless it is synthetic. */ private void enterMember(ClassSymbol c, Symbol sym) { - if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC) + // Synthetic members are not entered -- reason lost to history (optimization?). + // Lambda methods must be entered because they may have inner classes (which reference them) + if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC || sym.name.startsWith(names.lambda)) c.members_field.enter(sym); } diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Feb 15 11:26:11 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Feb 15 18:40:38 2013 -0800 @@ -39,6 +39,9 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Attribute.RetentionPolicy; import com.sun.tools.javac.code.Attribute.TypeCompound; +import static com.sun.tools.javac.code.BoundKind.EXTENDS; +import static com.sun.tools.javac.code.BoundKind.SUPER; +import static com.sun.tools.javac.code.BoundKind.UNBOUND; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Types.UniqueType; @@ -126,10 +129,6 @@ */ ByteBuffer poolbuf = new ByteBuffer(POOL_BUF_SIZE); - /** An output buffer for type signatures. - */ - ByteBuffer sigbuf = new ByteBuffer(); - /** The constant pool. */ Pool pool; @@ -158,6 +157,9 @@ /** Access to files. */ private final JavaFileManager fileManager; + /** Sole signature generator */ + private final CWSignatureGenerator signatureGen; + /** The tags and constants used in compressed stackmap. */ static final int SAME_FRAME_SIZE = 64; static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; @@ -185,6 +187,7 @@ source = Source.instance(context); types = Types.instance(context); fileManager = context.get(JavaFileManager.class); + signatureGen = new CWSignatureGenerator(types); verbose = options.isSet(VERBOSE); scramble = options.isSet("-scramble"); @@ -270,172 +273,81 @@ buf.elems[adr+3] = (byte)((x ) & 0xFF); } -/****************************************************************** - * Signature Generation - ******************************************************************/ - - /** Assemble signature of given type in string buffer. + /** + * Signature Generation */ - void assembleSig(Type type) { - type = type.unannotatedType(); - switch (type.getTag()) { - case BYTE: - sigbuf.appendByte('B'); - break; - case SHORT: - sigbuf.appendByte('S'); - break; - case CHAR: - sigbuf.appendByte('C'); - break; - case INT: - sigbuf.appendByte('I'); - break; - case LONG: - sigbuf.appendByte('J'); - break; - case FLOAT: - sigbuf.appendByte('F'); - break; - case DOUBLE: - sigbuf.appendByte('D'); - break; - case BOOLEAN: - sigbuf.appendByte('Z'); - break; - case VOID: - sigbuf.appendByte('V'); - break; - case CLASS: - sigbuf.appendByte('L'); - assembleClassSig(type); - sigbuf.appendByte(';'); - break; - case ARRAY: - ArrayType at = (ArrayType)type; - sigbuf.appendByte('['); - assembleSig(at.elemtype); - break; - case METHOD: - MethodType mt = (MethodType)type; - sigbuf.appendByte('('); - assembleSig(mt.argtypes); - sigbuf.appendByte(')'); - assembleSig(mt.restype); - if (hasTypeVar(mt.thrown)) { - for (List l = mt.thrown; l.nonEmpty(); l = l.tail) { - sigbuf.appendByte('^'); - assembleSig(l.head); - } + private class CWSignatureGenerator extends Types.SignatureGenerator { + + /** + * An output buffer for type signatures. + */ + ByteBuffer sigbuf = new ByteBuffer(); + + CWSignatureGenerator(Types types) { + super(types); + } + + /** + * Assemble signature of given type in string buffer. + * Check for uninitialized types before calling the general case. + */ + @Override + public void assembleSig(Type type) { + type = type.unannotatedType(); + switch (type.getTag()) { + case UNINITIALIZED_THIS: + case UNINITIALIZED_OBJECT: + // we don't yet have a spec for uninitialized types in the + // local variable table + assembleSig(types.erasure(((UninitializedType)type).qtype)); + break; + default: + super.assembleSig(type); } - break; - case WILDCARD: { - WildcardType ta = (WildcardType) type; - switch (ta.kind) { - case SUPER: - sigbuf.appendByte('-'); - assembleSig(ta.type); - break; - case EXTENDS: - sigbuf.appendByte('+'); - assembleSig(ta.type); - break; - case UNBOUND: - sigbuf.appendByte('*'); - break; - default: - throw new AssertionError(ta.kind); - } - break; + } + + @Override + protected void append(char ch) { + sigbuf.appendByte(ch); + } + + @Override + protected void append(byte[] ba) { + sigbuf.appendBytes(ba); + } + + @Override + protected void append(Name name) { + sigbuf.appendName(name); } - case TYPEVAR: - sigbuf.appendByte('T'); - sigbuf.appendName(type.tsym.name); - sigbuf.appendByte(';'); - break; - case FORALL: - ForAll ft = (ForAll)type; - assembleParamsSig(ft.tvars); - assembleSig(ft.qtype); - break; - case UNINITIALIZED_THIS: - case UNINITIALIZED_OBJECT: - // we don't yet have a spec for uninitialized types in the - // local variable table - assembleSig(types.erasure(((UninitializedType)type).qtype)); - break; - default: - throw new AssertionError("typeSig " + type.getTag()); + + @Override + protected void classReference(ClassSymbol c) { + enterInner(c); + } + + private void reset() { + sigbuf.reset(); + } + + private Name toName() { + return sigbuf.toName(names); + } + + private boolean isEmpty() { + return sigbuf.length == 0; } } - boolean hasTypeVar(List l) { - while (l.nonEmpty()) { - if (l.head.hasTag(TYPEVAR)) return true; - l = l.tail; - } - return false; - } - - void assembleClassSig(Type type) { - type = type.unannotatedType(); - ClassType ct = (ClassType)type; - ClassSymbol c = (ClassSymbol)ct.tsym; - enterInner(c); - Type outer = ct.getEnclosingType(); - if (outer.allparams().nonEmpty()) { - boolean rawOuter = - c.owner.kind == MTH || // either a local class - c.name == names.empty; // or anonymous - assembleClassSig(rawOuter - ? types.erasure(outer) - : outer); - sigbuf.appendByte('.'); - Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname)); - sigbuf.appendName(rawOuter - ? c.flatname.subName(c.owner.enclClass().flatname.getByteLength()+1,c.flatname.getByteLength()) - : c.name); - } else { - sigbuf.appendBytes(externalize(c.flatname)); - } - if (ct.getTypeArguments().nonEmpty()) { - sigbuf.appendByte('<'); - assembleSig(ct.getTypeArguments()); - sigbuf.appendByte('>'); - } - } - - - void assembleSig(List types) { - for (List ts = types; ts.nonEmpty(); ts = ts.tail) - assembleSig(ts.head); - } - - void assembleParamsSig(List typarams) { - sigbuf.appendByte('<'); - for (List ts = typarams; ts.nonEmpty(); ts = ts.tail) { - TypeVar tvar = (TypeVar)ts.head; - sigbuf.appendName(tvar.tsym.name); - List bounds = types.getBounds(tvar); - if ((bounds.head.tsym.flags() & INTERFACE) != 0) { - sigbuf.appendByte(':'); - } - for (List l = bounds; l.nonEmpty(); l = l.tail) { - sigbuf.appendByte(':'); - assembleSig(l.head); - } - } - sigbuf.appendByte('>'); - } - - /** Return signature of given type + /** + * Return signature of given type */ Name typeSig(Type type) { - Assert.check(sigbuf.length == 0); + Assert.check(signatureGen.isEmpty()); //- System.out.println(" ? " + type); - assembleSig(type); - Name n = sigbuf.toName(names); - sigbuf.reset(); + signatureGen.assembleSig(type); + Name n = signatureGen.toName(); + signatureGen.reset(); //- System.out.println(" " + n); return n; } @@ -711,7 +623,7 @@ (flags & (SYNTHETIC|BRIDGE)) != SYNTHETIC && (flags & ANONCONSTR) == 0 && (!types.isSameType(sym.type, sym.erasure(types)) || - hasTypeVar(sym.type.getThrownTypes()))) { + signatureGen.hasTypeVar(sym.type.getThrownTypes()))) { // note that a local class with captured variables // will get a signature attribute int alenIdx = writeAttr(names.Signature); @@ -1730,7 +1642,7 @@ Assert.check((c.flags() & COMPOUND) == 0); databuf.reset(); poolbuf.reset(); - sigbuf.reset(); + signatureGen.reset(); pool = c.pool; innerClasses = null; innerClassesQueue = null; @@ -1791,12 +1703,12 @@ if (sigReq) { Assert.check(source.allowGenerics()); int alenIdx = writeAttr(names.Signature); - if (typarams.length() != 0) assembleParamsSig(typarams); - assembleSig(supertype); + if (typarams.length() != 0) signatureGen.assembleParamsSig(typarams); + signatureGen.assembleSig(supertype); for (List l = interfaces; l.nonEmpty(); l = l.tail) - assembleSig(l.head); - databuf.appendChar(pool.put(sigbuf.toName(names))); - sigbuf.reset(); + signatureGen.assembleSig(l.head); + databuf.appendChar(pool.put(signatureGen.toName())); + signatureGen.reset(); endAttr(alenIdx); acount++; } diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/src/share/classes/com/sun/tools/javac/util/Names.java --- a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java Fri Feb 15 11:26:11 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java Fri Feb 15 18:40:38 2013 -0800 @@ -73,6 +73,7 @@ public final Name clone; public final Name close; public final Name compareTo; + public final Name deserializeLambda; public final Name desiredAssertionStatus; public final Name equals; public final Name error; @@ -174,6 +175,7 @@ //lambda-related public final Name lambda; public final Name metaFactory; + public final Name altMetaFactory; public final Name.Table table; @@ -207,6 +209,7 @@ clone = fromString("clone"); close = fromString("close"); compareTo = fromString("compareTo"); + deserializeLambda = fromString("$deserializeLambda$"); desiredAssertionStatus = fromString("desiredAssertionStatus"); equals = fromString("equals"); error = fromString(""); @@ -306,8 +309,9 @@ package_info = fromString("package-info"); //lambda-related - lambda = fromString("lambda"); + lambda = fromString("lambda$"); metaFactory = fromString("metaFactory"); + altMetaFactory = fromString("altMetaFactory"); } protected Name.Table createTable(Options options) { diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/test/tools/javac/lambda/LambdaInnerTypeVarArgs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/LambdaInnerTypeVarArgs.java Fri Feb 15 18:40:38 2013 -0800 @@ -0,0 +1,80 @@ +/* + * 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 8005653 + * @summary A lambda containing an inner class referencing an external type var in class parameter type + * @author Robert Field + * @run main LambdaInnerTypeVarArgs + */ + +import java.io.Serializable; +import java.util.List; +import java.util.ArrayList; + +public class LambdaInnerTypeVarArgs { + + static int assertionCount = 0; + + static void assertTrue(boolean cond) { + assertionCount++; + if (!cond) + throw new AssertionError(); + } + + interface I { + C doit(); + } + + abstract class C { + abstract Object it(); + } + + class TV { + C go() { + List ls = new ArrayList<>(); + ls.add("Oh"); + ls.add("my"); + return foo(ls).doit(); + } + + I foo(List r) { + return () -> new C() { + List xxxxx = r; + @Override + Object it() { return xxxxx; }; + }; + } + } + + void test1() { + assertTrue(((List)(new TV().go().it())).get(0).equals("Oh")); + } + + public static void main(String[] args) { + LambdaInnerTypeVarArgs t = new LambdaInnerTypeVarArgs(); + t.test1(); + assertTrue(assertionCount == 1); + } +} diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/test/tools/javac/lambda/LambdaInnerTypeVarReflect.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/LambdaInnerTypeVarReflect.java Fri Feb 15 18:40:38 2013 -0800 @@ -0,0 +1,86 @@ +/* + * 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 8005653 + * @summary A lambda containing an inner class referencing an external type var + * @author Robert Field + * @run main LambdaInnerTypeVarReflect + */ + +import java.io.StringWriter; +import java.io.PrintWriter; +import java.io.IOException; + +public class LambdaInnerTypeVarReflect { + + static int assertionCount = 0; + + static void assertTrue(boolean cond) { + assertionCount++; + if (!cond) + throw new AssertionError(); + } + + interface I { + C doit(); + } + + abstract class C { + abstract Object it(); + } + + class TV { + C go() { + return foo("Frump").doit(); + } + + I foo(RRRRR r) { + return () -> new C() { + public RRRRR xxxxx = r; + @Override + Object it() { return xxxxx; }; + }; + } + } + + void test1() throws IOException { + char[] buffer = new char[1024]; + String innerName = new TV().go().getClass().getName(); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int exitCode = com.sun.tools.javap.Main.run(new String[] {innerName}, pw); + assertTrue(exitCode == 0); + + String javapOut = sw.toString(); + assertTrue(javapOut.contains(innerName)); + assertTrue(!javapOut.contains("RRRRR")); + } + + public static void main(String[] args) throws IOException { + LambdaInnerTypeVarReflect t = new LambdaInnerTypeVarReflect(); + t.test1(); + assertTrue(assertionCount == 3); + } +} diff -r 05b5bf59c9d3 -r 7cf27559c8df langtools/test/tools/javac/lambda/MethodReference61.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MethodReference61.java Fri Feb 15 18:40:38 2013 -0800 @@ -0,0 +1,43 @@ +/* + * 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 8006763 + * @summary super in method reference used in anonymous class + */ +public class MethodReference61 { + interface SAM { + void m(); + } + + static class MyTester { + public void ifoo() { } + } + + public static void main(String args[]) { + MyTester t = new MyTester() { + SAM s = super::ifoo; + }; + } +}