diff -r 9fb4f223a90d -r f1f605f85850 src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Feb 15 11:26:11 2013 -0800 +++ b/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(); + } } }