src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java

Fri, 26 Apr 2013 10:17:01 +0100

author
vromero
date
Fri, 26 Apr 2013 10:17:01 +0100
changeset 1713
2ca9e7d50136
parent 1667
a200d8ccfe47
child 1717
8e27e84de2e9
permissions
-rw-r--r--

8008562: javac, a refactoring to Bits is necessary in order to provide a change history
Reviewed-by: mcimadamore

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 package com.sun.tools.javac.comp;
    27 import com.sun.tools.javac.tree.*;
    28 import com.sun.tools.javac.tree.JCTree;
    29 import com.sun.tools.javac.tree.JCTree.*;
    30 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    31 import com.sun.tools.javac.tree.TreeMaker;
    32 import com.sun.tools.javac.tree.TreeScanner;
    33 import com.sun.tools.javac.tree.TreeTranslator;
    34 import com.sun.tools.javac.code.Kinds;
    35 import com.sun.tools.javac.code.Scope;
    36 import com.sun.tools.javac.code.Symbol;
    37 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    38 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
    39 import com.sun.tools.javac.code.Symbol.MethodSymbol;
    40 import com.sun.tools.javac.code.Symbol.VarSymbol;
    41 import com.sun.tools.javac.code.Symtab;
    42 import com.sun.tools.javac.code.Type;
    43 import com.sun.tools.javac.code.Type.ClassType;
    44 import com.sun.tools.javac.code.Type.MethodType;
    45 import com.sun.tools.javac.code.Types;
    46 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzer.*;
    47 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    48 import com.sun.tools.javac.jvm.*;
    49 import com.sun.tools.javac.util.*;
    50 import com.sun.tools.javac.util.List;
    51 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    52 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
    54 import java.util.HashMap;
    55 import java.util.LinkedHashMap;
    56 import java.util.Map;
    58 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    59 import static com.sun.tools.javac.code.Flags.*;
    60 import static com.sun.tools.javac.code.Kinds.*;
    61 import static com.sun.tools.javac.code.TypeTag.*;
    62 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    64 /**
    65  * This pass desugars lambda expressions into static methods
    66  *
    67  *  <p><b>This is NOT part of any supported API.
    68  *  If you write code that depends on this, you do so at your own risk.
    69  *  This code and its internal interfaces are subject to change or
    70  *  deletion without notice.</b>
    71  */
    72 public class LambdaToMethod extends TreeTranslator {
    74     private Lower lower;
    75     private Names names;
    76     private Symtab syms;
    77     private Resolve rs;
    78     private TreeMaker make;
    79     private Types types;
    80     private TransTypes transTypes;
    81     private Env<AttrContext> attrEnv;
    83     /** the analyzer scanner */
    84     private LambdaAnalyzer analyzer;
    86     /** map from lambda trees to translation contexts */
    87     private Map<JCTree, TranslationContext<?>> contextMap;
    89     /** current translation context (visitor argument) */
    90     private TranslationContext<?> context;
    92     /** info about the current class being processed */
    93     private KlassInfo kInfo;
    95     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
    96     public static final int FLAG_SERIALIZABLE = 1 << 0;
    98     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
    99     public static final int FLAG_MARKERS = 1 << 1;
   101     private class KlassInfo {
   103         /**
   104          * list of methods to append
   105          */
   106         private ListBuffer<JCTree> appendedMethodList;
   108         /**
   109          * list of deserialization cases
   110          */
   111         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   113        /**
   114          * deserialize method symbol
   115          */
   116         private final MethodSymbol deserMethodSym;
   118         /**
   119          * deserialize method parameter symbol
   120          */
   121         private final VarSymbol deserParamSym;
   123         private KlassInfo(Symbol kSym) {
   124             appendedMethodList = ListBuffer.lb();
   125             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
   126             long flags = PRIVATE | STATIC | SYNTHETIC;
   127             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
   128                     List.<Type>nil(), syms.methodClass);
   129             deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym);
   130             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
   131                     syms.serializedLambdaType, deserMethodSym);
   132         }
   134         private void addMethod(JCTree decl) {
   135             appendedMethodList = appendedMethodList.prepend(decl);
   136         }
   137     }
   139     // <editor-fold defaultstate="collapsed" desc="Instantiating">
   140     private static final Context.Key<LambdaToMethod> unlambdaKey =
   141             new Context.Key<LambdaToMethod>();
   143     public static LambdaToMethod instance(Context context) {
   144         LambdaToMethod instance = context.get(unlambdaKey);
   145         if (instance == null) {
   146             instance = new LambdaToMethod(context);
   147         }
   148         return instance;
   149     }
   151     private LambdaToMethod(Context context) {
   152         lower = Lower.instance(context);
   153         names = Names.instance(context);
   154         syms = Symtab.instance(context);
   155         rs = Resolve.instance(context);
   156         make = TreeMaker.instance(context);
   157         types = Types.instance(context);
   158         transTypes = TransTypes.instance(context);
   159         analyzer = new LambdaAnalyzer();
   160     }
   161     // </editor-fold>
   163     // <editor-fold defaultstate="collapsed" desc="translate methods">
   164     @Override
   165     public <T extends JCTree> T translate(T tree) {
   166         TranslationContext<?> newContext = contextMap.get(tree);
   167         return translate(tree, newContext != null ? newContext : context);
   168     }
   170     public <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
   171         TranslationContext<?> prevContext = context;
   172         try {
   173             context = newContext;
   174             return super.translate(tree);
   175         }
   176         finally {
   177             context = prevContext;
   178         }
   179     }
   181     public <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
   182         ListBuffer<T> buf = ListBuffer.lb();
   183         for (T tree : trees) {
   184             buf.append(translate(tree, newContext));
   185         }
   186         return buf.toList();
   187     }
   189     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
   190         this.make = make;
   191         this.attrEnv = env;
   192         this.context = null;
   193         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
   194         return translate(cdef);
   195     }
   196     // </editor-fold>
   198     // <editor-fold defaultstate="collapsed" desc="visitor methods">
   199     /**
   200      * Visit a class.
   201      * Maintain the translatedMethodList across nested classes.
   202      * Append the translatedMethodList to the class after it is translated.
   203      * @param tree
   204      */
   205     @Override
   206     public void visitClassDef(JCClassDecl tree) {
   207         if (tree.sym.owner.kind == PCK) {
   208             //analyze class
   209             analyzer.analyzeClass(tree);
   210         }
   211         KlassInfo prevKlassInfo = kInfo;
   212         try {
   213             kInfo = new KlassInfo(tree.sym);
   214             super.visitClassDef(tree);
   215             if (!kInfo.deserializeCases.isEmpty()) {
   216                 kInfo.addMethod(makeDeserializeMethod(tree.sym));
   217             }
   218             //add all translated instance methods here
   219             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
   220             tree.defs = tree.defs.appendList(newMethods);
   221             for (JCTree lambda : newMethods) {
   222                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
   223             }
   224             result = tree;
   225         } finally {
   226             kInfo = prevKlassInfo;
   227         }
   228     }
   230     /**
   231      * Translate a lambda into a method to be inserted into the class.
   232      * Then replace the lambda site with an invokedynamic call of to lambda
   233      * meta-factory, which will use the lambda method.
   234      * @param tree
   235      */
   236     @Override
   237     public void visitLambda(JCLambda tree) {
   238         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
   239         MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
   240         MethodType lambdaType = (MethodType) sym.type;
   242         //create the method declaration hoisting the lambda body
   243         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
   244                 sym.name,
   245                 make.QualIdent(lambdaType.getReturnType().tsym),
   246                 List.<JCTypeParameter>nil(),
   247                 localContext.syntheticParams,
   248                 lambdaType.getThrownTypes() == null ?
   249                     List.<JCExpression>nil() :
   250                     make.Types(lambdaType.getThrownTypes()),
   251                 null,
   252                 null);
   253         lambdaDecl.sym = sym;
   254         lambdaDecl.type = lambdaType;
   256         //translate lambda body
   257         //As the lambda body is translated, all references to lambda locals,
   258         //captured variables, enclosing members are adjusted accordingly
   259         //to refer to the static method parameters (rather than i.e. acessing to
   260         //captured members directly).
   261         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
   263         //Add the method to the list of methods to be added to this class.
   264         kInfo.addMethod(lambdaDecl);
   266         //now that we have generated a method for the lambda expression,
   267         //we can translate the lambda into a method reference pointing to the newly
   268         //created method.
   269         //
   270         //Note that we need to adjust the method handle so that it will match the
   271         //signature of the SAM descriptor - this means that the method reference
   272         //should be added the following synthetic arguments:
   273         //
   274         // * the "this" argument if it is an instance method
   275         // * enclosing locals captured by the lambda expression
   277         ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
   279         if (!sym.isStatic()) {
   280             syntheticInits.append(makeThis(
   281                     sym.owner.enclClass().asType(),
   282                     localContext.owner.enclClass()));
   283         }
   285         //add captured locals
   286         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
   287             if (fv != localContext.self) {
   288                 JCTree captured_local = make.Ident(fv).setType(fv.type);
   289                 syntheticInits.append((JCExpression) captured_local);
   290             }
   291         }
   293         //then, determine the arguments to the indy call
   294         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   296         //build a sam instance using an indy call to the meta-factory
   297         int refKind = referenceKind(sym);
   299         //convert to an invokedynamic call
   300         result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args);
   301     }
   303     private JCIdent makeThis(Type type, Symbol owner) {
   304         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
   305                 names._this,
   306                 type,
   307                 owner);
   308         return make.Ident(_this);
   309     }
   311     /**
   312      * Translate a method reference into an invokedynamic call to the
   313      * meta-factory.
   314      * @param tree
   315      */
   316     @Override
   317     public void visitReference(JCMemberReference tree) {
   318         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   320         //first determine the method symbol to be used to generate the sam instance
   321         //this is either the method reference symbol, or the bridged reference symbol
   322         Symbol refSym = localContext.needsBridge() ?
   323             localContext.bridgeSym :
   324             tree.sym;
   326         //build the bridge method, if needed
   327         if (localContext.needsBridge()) {
   328             bridgeMemberReference(tree, localContext);
   329         }
   331         //the qualifying expression is treated as a special captured arg
   332         JCExpression init;
   333         switch(tree.kind) {
   335             case IMPLICIT_INNER:    /** Inner :: new */
   336             case SUPER:             /** super :: instMethod */
   337                 init = makeThis(
   338                     localContext.owner.enclClass().asType(),
   339                     localContext.owner.enclClass());
   340                 break;
   342             case BOUND:             /** Expr :: instMethod */
   343                 init = tree.getQualifierExpression();
   344                 break;
   346             case UNBOUND:           /** Type :: instMethod */
   347             case STATIC:            /** Type :: staticMethod */
   348             case TOPLEVEL:          /** Top level :: new */
   349             case ARRAY_CTOR:        /** ArrayType :: new */
   350                 init = null;
   351                 break;
   353             default:
   354                 throw new InternalError("Should not have an invalid kind");
   355         }
   357         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
   360         //build a sam instance using an indy call to the meta-factory
   361         result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args);
   362     }
   364     /**
   365      * Translate identifiers within a lambda to the mapped identifier
   366      * @param tree
   367      */
   368     @Override
   369     public void visitIdent(JCIdent tree) {
   370         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
   371             super.visitIdent(tree);
   372         } else {
   373             LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
   374             if (lambdaContext.getSymbolMap(PARAM).containsKey(tree.sym)) {
   375                 Symbol translatedSym = lambdaContext.getSymbolMap(PARAM).get(tree.sym);
   376                 result = make.Ident(translatedSym).setType(tree.type);
   377             } else if (lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   378                 Symbol translatedSym = lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
   379                 result = make.Ident(translatedSym).setType(tree.type);
   380             } else if (lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   381                 Symbol translatedSym = lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   382                 result = make.Ident(translatedSym).setType(translatedSym.type);
   383             } else if (lambdaContext.getSymbolMap(CAPTURED_VAR).containsKey(tree.sym)) {
   384                 Symbol translatedSym = lambdaContext.getSymbolMap(CAPTURED_VAR).get(tree.sym);
   385                 result = make.Ident(translatedSym).setType(tree.type);
   386             } else {
   387                 //access to untranslated symbols (i.e. compile-time constants,
   388                 //members defined inside the lambda body, etc.) )
   389                 super.visitIdent(tree);
   390             }
   391         }
   392     }
   394     @Override
   395     public void visitVarDef(JCVariableDecl tree) {
   396         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
   397         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
   398             JCExpression init = translate(tree.init);
   399             result = make.VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
   400         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
   401             JCExpression init = translate(tree.init);
   402             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
   403             result = make.VarDef(xsym, init);
   404             // Replace the entered symbol for this variable
   405             Scope sc = tree.sym.owner.members();
   406             if (sc != null) {
   407                 sc.remove(tree.sym);
   408                 sc.enter(xsym);
   409             }
   410         } else {
   411             super.visitVarDef(tree);
   412         }
   413     }
   415     // </editor-fold>
   417     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
   419     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
   420         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
   421                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
   422                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
   423     }
   425     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
   426         Type restype = lambdaMethodDecl.type.getReturnType();
   427         boolean isLambda_void = expr.type.hasTag(VOID);
   428         boolean isTarget_void = restype.hasTag(VOID);
   429         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   430         if (isTarget_void) {
   431             //target is void:
   432             // BODY;
   433             JCStatement stat = make.Exec(expr);
   434             return make.Block(0, List.<JCStatement>of(stat));
   435         } else if (isLambda_void && isTarget_Void) {
   436             //void to Void conversion:
   437             // BODY; return null;
   438             ListBuffer<JCStatement> stats = ListBuffer.lb();
   439             stats.append(make.Exec(expr));
   440             stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   441             return make.Block(0, stats.toList());
   442         } else {
   443             //non-void to non-void conversion:
   444             // return (TYPE)BODY;
   445             JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
   446             return make.Block(0, List.<JCStatement>of(make.Return(retExpr)));
   447         }
   448     }
   450     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
   451         final Type restype = lambdaMethodDecl.type.getReturnType();
   452         final boolean isTarget_void = restype.hasTag(VOID);
   453         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
   455         class LambdaBodyTranslator extends TreeTranslator {
   457             @Override
   458             public void visitClassDef(JCClassDecl tree) {
   459                 //do NOT recurse on any inner classes
   460                 result = tree;
   461             }
   463             @Override
   464             public void visitLambda(JCLambda tree) {
   465                 //do NOT recurse on any nested lambdas
   466                 result = tree;
   467             }
   469             @Override
   470             public void visitReturn(JCReturn tree) {
   471                 boolean isLambda_void = tree.expr == null;
   472                 if (isTarget_void && !isLambda_void) {
   473                     //Void to void conversion:
   474                     // { TYPE $loc = RET-EXPR; return; }
   475                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
   476                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
   477                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
   478                 } else if (!isTarget_void || !isLambda_void) {
   479                     //non-void to non-void conversion:
   480                     // return (TYPE)RET-EXPR;
   481                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
   482                     result = tree;
   483                 } else {
   484                     result = tree;
   485                 }
   487             }
   488         }
   490         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
   491         if (completeNormally && isTarget_Void) {
   492             //there's no return statement and the lambda (possibly inferred)
   493             //return type is java.lang.Void; emit a synthetic return statement
   494             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
   495         }
   496         return trans_block;
   497     }
   499     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
   500         ListBuffer<JCCase> cases = ListBuffer.lb();
   501         ListBuffer<JCBreak> breaks = ListBuffer.lb();
   502         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
   503             JCBreak br = make.Break(null);
   504             breaks.add(br);
   505             List<JCStatement> stmts = entry.getValue().append(br).toList();
   506             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
   507         }
   508         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
   509         for (JCBreak br : breaks) {
   510             br.target = sw;
   511         }
   512         JCBlock body = make.Block(0L, List.<JCStatement>of(
   513                 sw,
   514                 make.Throw(makeNewClass(
   515                     syms.illegalArgumentExceptionType,
   516                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
   517         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
   518                         names.deserializeLambda,
   519                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
   520                         List.<JCTypeParameter>nil(),
   521                         List.of(make.VarDef(kInfo.deserParamSym, null)),
   522                         List.<JCExpression>nil(),
   523                         body,
   524                         null);
   525         deser.sym = kInfo.deserMethodSym;
   526         deser.type = kInfo.deserMethodSym.type;
   527         //System.err.printf("DESER: '%s'\n", deser);
   528         return deser;
   529     }
   531     /** Make an attributed class instance creation expression.
   532      *  @param ctype    The class type.
   533      *  @param args     The constructor arguments.
   534      */
   535     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   536         JCNewClass tree = make.NewClass(null,
   537             null, make.QualIdent(ctype.tsym), args, null);
   538         tree.constructor = rs.resolveConstructor(
   539             null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil());
   540         tree.type = ctype;
   541         return tree;
   542     }
   544     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   545             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   546         String functionalInterfaceClass = classSig(targetType);
   547         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   548         String functionalInterfaceMethodSignature = methodSig(types.erasure(samSym.type));
   549         String implClass = classSig(types.erasure(refSym.owner.type));
   550         String implMethodName = refSym.getQualifiedName().toString();
   551         String implMethodSignature = methodSig(types.erasure(refSym.type));
   553         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   554         ListBuffer<JCExpression> serArgs = ListBuffer.lb();
   555         int i = 0;
   556         for (Type t : indyType.getParameterTypes()) {
   557             List<JCExpression> indexAsArg = ListBuffer.<JCExpression>lb().append(make.Literal(i)).toList();
   558             List<Type> argTypes = ListBuffer.<Type>lb().append(syms.intType).toList();
   559             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
   560             ++i;
   561         }
   562         JCStatement stmt = make.If(
   563                 deserTest(deserTest(deserTest(deserTest(deserTest(
   564                     kindTest,
   565                     "getFunctionalInterfaceClass", functionalInterfaceClass),
   566                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
   567                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
   568                     "getImplClass", implClass),
   569                     "getImplMethodSignature", implMethodSignature),
   570                 make.Return(makeIndyCall(
   571                     pos,
   572                     syms.lambdaMetafactory,
   573                     names.altMetaFactory,
   574                     staticArgs, indyType, serArgs.toList())),
   575                 null);
   576         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
   577         if (stmts == null) {
   578             stmts = ListBuffer.lb();
   579             kInfo.deserializeCases.put(implMethodName, stmts);
   580         }
   581         /****
   582         System.err.printf("+++++++++++++++++\n");
   583         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
   584         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
   585         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
   586         System.err.printf("*implMethodKind: %d\n", implMethodKind);
   587         System.err.printf("*implClass: '%s'\n", implClass);
   588         System.err.printf("*implMethodName: '%s'\n", implMethodName);
   589         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
   590         ****/
   591         stmts.append(stmt);
   592     }
   594     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
   595         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
   596         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
   597         testExpr.setType(syms.booleanType);
   598         return testExpr;
   599     }
   601     private JCExpression deserTest(JCExpression prev, String func, String lit) {
   602         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
   603         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
   604         JCMethodInvocation eqtest = make.Apply(
   605                 List.<JCExpression>nil(),
   606                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
   607                 List.<JCExpression>of(make.Literal(lit)));
   608         eqtest.setType(syms.booleanType);
   609         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
   610         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
   611         compound.setType(syms.booleanType);
   612         return compound;
   613     }
   615     private JCExpression deserGetter(String func, Type type) {
   616         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
   617     }
   619     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
   620         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
   621         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
   622         return make.Apply(
   623                     List.<JCExpression>nil(),
   624                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
   625                     args).setType(type);
   626     }
   628     /**
   629      * Create new synthetic method with given flags, name, type, owner
   630      */
   631     private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
   632         return new MethodSymbol(flags | SYNTHETIC, name, type, owner);
   633     }
   635     /**
   636      * Create new synthetic variable with given flags, name, type, owner
   637      */
   638     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
   639         return makeSyntheticVar(flags, names.fromString(name), type, owner);
   640     }
   642     /**
   643      * Create new synthetic variable with given flags, name, type, owner
   644      */
   645     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
   646         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
   647     }
   649     /**
   650      * Set varargsElement field on a given tree (must be either a new class tree
   651      * or a method call tree)
   652      */
   653     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
   654         if (varargsElement != null) {
   655             switch (tree.getTag()) {
   656                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
   657                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
   658                 default: throw new AssertionError();
   659             }
   660         }
   661     }
   663     /**
   664      * Convert method/constructor arguments by inserting appropriate cast
   665      * as required by type-erasure - this is needed when bridging a lambda/method
   666      * reference, as the bridged signature might require downcast to be compatible
   667      * with the generated signature.
   668      */
   669     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
   670        Assert.check(meth.kind == Kinds.MTH);
   671        List<Type> formals = types.erasure(meth.type).getParameterTypes();
   672        if (varargsElement != null) {
   673            Assert.check((meth.flags() & VARARGS) != 0);
   674        }
   675        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
   676     }
   678     // </editor-fold>
   680     /**
   681      * Generate an adapter method "bridge" for a method reference which cannot
   682      * be used directly.
   683      */
   684     private class MemberReferenceBridger {
   686         private final JCMemberReference tree;
   687         private final ReferenceTranslationContext localContext;
   688         private final ListBuffer<JCExpression> args = ListBuffer.lb();
   689         private final ListBuffer<JCVariableDecl> params = ListBuffer.lb();
   691         MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
   692             this.tree = tree;
   693             this.localContext = localContext;
   694         }
   696         /**
   697          * Generate the bridge
   698          */
   699         JCMethodDecl bridge() {
   700             int prevPos = make.pos;
   701             try {
   702                 make.at(tree);
   703                 Type samDesc = localContext.bridgedRefSig();
   704                 List<Type> samPTypes = samDesc.getParameterTypes();
   706                 //an extra argument is prepended to the signature of the bridge in case
   707                 //the member reference is an instance method reference (in which case
   708                 //the receiver expression is passed to the bridge itself).
   709                 Type recType = null;
   710                 switch (tree.kind) {
   711                     case IMPLICIT_INNER:
   712                         recType = tree.sym.owner.type.getEnclosingType();
   713                         break;
   714                     case BOUND:
   715                         recType = tree.getQualifierExpression().type;
   716                         break;
   717                     case UNBOUND:
   718                         recType = samPTypes.head;
   719                         samPTypes = samPTypes.tail;
   720                         break;
   721                 }
   723                 //generate the parameter list for the bridged member reference - the
   724                 //bridge signature will match the signature of the target sam descriptor
   726                 VarSymbol rcvr = (recType == null)
   727                         ? null
   728                         : addParameter("rec$", recType, false);
   730                 List<Type> refPTypes = tree.sym.type.getParameterTypes();
   731                 int refSize = refPTypes.size();
   732                 int samSize = samPTypes.size();
   733                 // Last parameter to copy from referenced method
   734                 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
   736                 List<Type> l = refPTypes;
   737                 // Use parameter types of the referenced method, excluding final var args
   738                 for (int i = 0; l.nonEmpty() && i < last; ++i) {
   739                     addParameter("x$" + i, l.head, true);
   740                     l = l.tail;
   741                 }
   742                 // Flatten out the var args
   743                 for (int i = last; i < samSize; ++i) {
   744                     addParameter("xva$" + i, tree.varargsElement, true);
   745                 }
   747                 //generate the bridge method declaration
   748                 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
   749                         localContext.bridgeSym.name,
   750                         make.QualIdent(samDesc.getReturnType().tsym),
   751                         List.<JCTypeParameter>nil(),
   752                         params.toList(),
   753                         tree.sym.type.getThrownTypes() == null
   754                         ? List.<JCExpression>nil()
   755                         : make.Types(tree.sym.type.getThrownTypes()),
   756                         null,
   757                         null);
   758                 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
   759                 bridgeDecl.type = localContext.bridgeSym.type =
   760                         types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
   762                 //bridge method body generation - this can be either a method call or a
   763                 //new instance creation expression, depending on the member reference kind
   764                 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
   765                         ? bridgeExpressionInvoke(makeReceiver(rcvr))
   766                         : bridgeExpressionNew();
   768                 //the body is either a return expression containing a method call,
   769                 //or the method call itself, depending on whether the return type of
   770                 //the bridge is non-void/void.
   771                 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
   773                 return bridgeDecl;
   774             } finally {
   775                 make.at(prevPos);
   776             }
   777         }
   778         //where
   779             private JCExpression makeReceiver(VarSymbol rcvr) {
   780                 if (rcvr == null) return null;
   781                 JCExpression rcvrExpr = make.Ident(rcvr);
   782                 Type rcvrType = tree.sym.enclClass().type;
   783                 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
   784                     rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
   785                 }
   786                 return rcvrExpr;
   787             }
   789         /**
   790          * determine the receiver of the bridged method call - the receiver can
   791          * be either the synthetic receiver parameter or a type qualifier; the
   792          * original qualifier expression is never used here, as it might refer
   793          * to symbols not available in the static context of the bridge
   794          */
   795         private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
   796             JCExpression qualifier =
   797                     tree.sym.isStatic() ?
   798                         make.Type(tree.sym.owner.type) :
   799                         (rcvr != null) ?
   800                             rcvr :
   801                             tree.getQualifierExpression();
   803             //create the qualifier expression
   804             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
   805             select.sym = tree.sym;
   806             select.type = tree.sym.erasure(types);
   808             //create the method call expression
   809             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
   810                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
   811                     setType(tree.sym.erasure(types).getReturnType());
   813             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
   814             setVarargsIfNeeded(apply, tree.varargsElement);
   815             return apply;
   816         }
   818         /**
   819          * the enclosing expression is either 'null' (no enclosing type) or set
   820          * to the first bridge synthetic parameter
   821          */
   822         private JCExpression bridgeExpressionNew() {
   823             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
   824                 //create the array creation expression
   825                 JCNewArray newArr = make.NewArray(
   826                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
   827                         List.of(make.Ident(params.first())),
   828                         null);
   829                 newArr.type = tree.getQualifierExpression().type;
   830                 return newArr;
   831             } else {
   832                 JCExpression encl = null;
   833                 switch (tree.kind) {
   834                     case UNBOUND:
   835                     case IMPLICIT_INNER:
   836                         encl = make.Ident(params.first());
   837                 }
   839                 //create the instance creation expression
   840                 JCNewClass newClass = make.NewClass(encl,
   841                         List.<JCExpression>nil(),
   842                         make.Type(tree.getQualifierExpression().type),
   843                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
   844                         null);
   845                 newClass.constructor = tree.sym;
   846                 newClass.constructorType = tree.sym.erasure(types);
   847                 newClass.type = tree.getQualifierExpression().type;
   848                 setVarargsIfNeeded(newClass, tree.varargsElement);
   849                 return newClass;
   850             }
   851         }
   853         private VarSymbol addParameter(String name, Type p, boolean genArg) {
   854             VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
   855             params.append(make.VarDef(vsym, null));
   856             if (genArg) {
   857                 args.append(make.Ident(vsym));
   858             }
   859             return vsym;
   860         }
   861     }
   863     /**
   864      * Bridges a member reference - this is needed when:
   865      * * Var args in the referenced method need to be flattened away
   866      * * super is used
   867      */
   868     private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
   869         kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
   870     }
   872     /**
   873      * Generate an indy method call to the meta factory
   874      */
   875     private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
   876             boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
   877         //determine the static bsm args
   878         Type mtype = types.erasure(tree.descriptorType);
   879         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
   880         List<Object> staticArgs = List.<Object>of(
   881                 new Pool.MethodHandle(ClassFile.REF_invokeInterface,
   882                     types.findDescriptorSymbol(tree.type.tsym), types),
   883                 new Pool.MethodHandle(refKind, refSym, types),
   884                 new MethodType(mtype.getParameterTypes(),
   885                         mtype.getReturnType(),
   886                         mtype.getThrownTypes(),
   887                         syms.methodClass));
   889         //computed indy arg types
   890         ListBuffer<Type> indy_args_types = ListBuffer.lb();
   891         for (JCExpression arg : indy_args) {
   892             indy_args_types.append(arg.type);
   893         }
   895         //finally, compute the type of the indy call
   896         MethodType indyType = new MethodType(indy_args_types.toList(),
   897                 tree.type,
   898                 List.<Type>nil(),
   899                 syms.methodClass);
   901         Name metafactoryName = needsAltMetafactory ?
   902                 names.altMetaFactory : names.metaFactory;
   904         if (needsAltMetafactory) {
   905             ListBuffer<Object> markers = ListBuffer.lb();
   906             for (Symbol t : tree.targets.tail) {
   907                 if (t != syms.serializableType.tsym) {
   908                     markers.append(t);
   909                 }
   910             }
   911             int flags = isSerializable? FLAG_SERIALIZABLE : 0;
   912             boolean hasMarkers = markers.nonEmpty();
   913             flags |= hasMarkers ? FLAG_MARKERS : 0;
   914             staticArgs = staticArgs.append(flags);
   915             if (hasMarkers) {
   916                 staticArgs = staticArgs.append(markers.length());
   917                 staticArgs = staticArgs.appendList(markers.toList());
   918             }
   919             if (isSerializable) {
   920                 addDeserializationCase(refKind, refSym, tree.type, samSym,
   921                         tree, staticArgs, indyType);
   922             }
   923         }
   925         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
   926     }
   928     /**
   929      * Generate an indy method call with given name, type and static bootstrap
   930      * arguments types
   931      */
   932     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
   933             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
   934         int prevPos = make.pos;
   935         try {
   936             make.at(pos);
   937             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
   938                     syms.stringType,
   939                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
   941             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
   942                     bsmName, bsm_staticArgs, List.<Type>nil());
   944             DynamicMethodSymbol dynSym =
   945                     new DynamicMethodSymbol(names.lambda,
   946                                             syms.noSymbol,
   947                                             bsm.isStatic() ?
   948                                                 ClassFile.REF_invokeStatic :
   949                                                 ClassFile.REF_invokeVirtual,
   950                                             (MethodSymbol)bsm,
   951                                             indyType,
   952                                             staticArgs.toArray());
   954             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
   955             qualifier.sym = dynSym;
   956             qualifier.type = indyType.getReturnType();
   958             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
   959             proxyCall.type = indyType.getReturnType();
   960             return proxyCall;
   961         } finally {
   962             make.at(prevPos);
   963         }
   964     }
   965     //where
   966     private List<Type> bsmStaticArgToTypes(List<Object> args) {
   967         ListBuffer<Type> argtypes = ListBuffer.lb();
   968         for (Object arg : args) {
   969             argtypes.append(bsmStaticArgToType(arg));
   970         }
   971         return argtypes.toList();
   972     }
   974     private Type bsmStaticArgToType(Object arg) {
   975         Assert.checkNonNull(arg);
   976         if (arg instanceof ClassSymbol) {
   977             return syms.classType;
   978         } else if (arg instanceof Integer) {
   979             return syms.intType;
   980         } else if (arg instanceof Long) {
   981             return syms.longType;
   982         } else if (arg instanceof Float) {
   983             return syms.floatType;
   984         } else if (arg instanceof Double) {
   985             return syms.doubleType;
   986         } else if (arg instanceof String) {
   987             return syms.stringType;
   988         } else if (arg instanceof Pool.MethodHandle) {
   989             return syms.methodHandleType;
   990         } else if (arg instanceof MethodType) {
   991             return syms.methodTypeType;
   992         } else {
   993             Assert.error("bad static arg " + arg.getClass());
   994             return null;
   995         }
   996     }
   998     /**
   999      * Get the opcode associated with this method reference
  1000      */
  1001     private int referenceKind(Symbol refSym) {
  1002         if (refSym.isConstructor()) {
  1003             return ClassFile.REF_newInvokeSpecial;
  1004         } else {
  1005             if (refSym.isStatic()) {
  1006                 return ClassFile.REF_invokeStatic;
  1007             } else if (refSym.enclClass().isInterface()) {
  1008                 return ClassFile.REF_invokeInterface;
  1009             } else {
  1010                 return (refSym.flags() & PRIVATE) != 0 ?
  1011                         ClassFile.REF_invokeSpecial :
  1012                         ClassFile.REF_invokeVirtual;
  1017     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1018     /**
  1019      * This visitor collects information about translation of a lambda expression.
  1020      * More specifically, it keeps track of the enclosing contexts and captured locals
  1021      * accessed by the lambda being translated (as well as other useful info).
  1022      */
  1023     class LambdaAnalyzer extends TreeScanner {
  1025         /** the frame stack - used to reconstruct translation info about enclosing scopes */
  1026         private List<Frame> frameStack;
  1028         /**
  1029          * keep the count of lambda expression (used to generate unambiguous
  1030          * names)
  1031          */
  1032         private int lambdaCount = 0;
  1034         /**
  1035          * keep the count of lambda expression defined in given context (used to
  1036          * generate unambiguous names for serializable lambdas)
  1037          */
  1038         private Map<String, Integer> serializableLambdaCounts =
  1039                 new HashMap<String, Integer>();
  1041         private Map<Symbol, JCClassDecl> localClassDefs;
  1043         /**
  1044          * maps for fake clinit symbols to be used as owners of lambda occurring in
  1045          * a static var init context
  1046          */
  1047         private Map<ClassSymbol, Symbol> clinits =
  1048                 new HashMap<ClassSymbol, Symbol>();
  1050         private void analyzeClass(JCClassDecl tree) {
  1051             frameStack = List.nil();
  1052             localClassDefs = new HashMap<Symbol, JCClassDecl>();
  1053             scan(tree);
  1056         @Override
  1057         public void visitBlock(JCBlock tree) {
  1058             List<Frame> prevStack = frameStack;
  1059             try {
  1060                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
  1061                     frameStack = frameStack.prepend(new Frame(tree));
  1063                 super.visitBlock(tree);
  1065             finally {
  1066                 frameStack = prevStack;
  1070         @Override
  1071         public void visitClassDef(JCClassDecl tree) {
  1072             List<Frame> prevStack = frameStack;
  1073             Map<String, Integer> prevSerializableLambdaCount =
  1074                     serializableLambdaCounts;
  1075             Map<ClassSymbol, Symbol> prevClinits = clinits;
  1076             try {
  1077                 serializableLambdaCounts = new HashMap<String, Integer>();
  1078                 prevClinits = new HashMap<ClassSymbol, Symbol>();
  1079                 if (tree.sym.owner.kind == MTH) {
  1080                     localClassDefs.put(tree.sym, tree);
  1082                 if (directlyEnclosingLambda() != null) {
  1083                     tree.sym.owner = owner();
  1084                     if (tree.sym.hasOuterInstance()) {
  1085                         //if a class is defined within a lambda, the lambda must capture
  1086                         //its enclosing instance (if any)
  1087                         TranslationContext<?> localContext = context();
  1088                         while (localContext != null) {
  1089                             if (localContext.tree.getTag() == LAMBDA) {
  1090                                 ((LambdaTranslationContext)localContext)
  1091                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
  1093                             localContext = localContext.prev;
  1097                 frameStack = frameStack.prepend(new Frame(tree));
  1098                 super.visitClassDef(tree);
  1100             finally {
  1101                 frameStack = prevStack;
  1102                 serializableLambdaCounts = prevSerializableLambdaCount;
  1103                 clinits = prevClinits;
  1107         @Override
  1108         public void visitIdent(JCIdent tree) {
  1109             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
  1110                 if (tree.sym.kind == VAR &&
  1111                         tree.sym.owner.kind == MTH &&
  1112                         tree.type.constValue() == null) {
  1113                     TranslationContext<?> localContext = context();
  1114                     while (localContext != null) {
  1115                         if (localContext.tree.getTag() == LAMBDA) {
  1116                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1117                             if (block == null) break;
  1118                             ((LambdaTranslationContext)localContext)
  1119                                     .addSymbol(tree.sym, CAPTURED_VAR);
  1121                         localContext = localContext.prev;
  1123                 } else if (tree.sym.owner.kind == TYP) {
  1124                     TranslationContext<?> localContext = context();
  1125                     while (localContext != null) {
  1126                         if (localContext.tree.hasTag(LAMBDA)) {
  1127                             JCTree block = capturedDecl(localContext.depth, tree.sym);
  1128                             if (block == null) break;
  1129                             switch (block.getTag()) {
  1130                                 case CLASSDEF:
  1131                                     JCClassDecl cdecl = (JCClassDecl)block;
  1132                                     ((LambdaTranslationContext)localContext)
  1133                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
  1134                                     break;
  1135                                 default:
  1136                                     Assert.error("bad block kind");
  1139                         localContext = localContext.prev;
  1143             super.visitIdent(tree);
  1146         @Override
  1147         public void visitLambda(JCLambda tree) {
  1148             List<Frame> prevStack = frameStack;
  1149             try {
  1150                 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
  1151                 frameStack = frameStack.prepend(new Frame(tree));
  1152                 for (JCVariableDecl param : tree.params) {
  1153                     context.addSymbol(param.sym, PARAM);
  1154                     frameStack.head.addLocal(param.sym);
  1156                 contextMap.put(tree, context);
  1157                 scan(tree.body);
  1158                 context.complete();
  1160             finally {
  1161                 frameStack = prevStack;
  1165         @Override
  1166         public void visitMethodDef(JCMethodDecl tree) {
  1167             List<Frame> prevStack = frameStack;
  1168             try {
  1169                 frameStack = frameStack.prepend(new Frame(tree));
  1170                 super.visitMethodDef(tree);
  1172             finally {
  1173                 frameStack = prevStack;
  1177         @Override
  1178         public void visitNewClass(JCNewClass tree) {
  1179             if (lambdaNewClassFilter(context(), tree)) {
  1180                 TranslationContext<?> localContext = context();
  1181                 while (localContext != null) {
  1182                     if (localContext.tree.getTag() == LAMBDA) {
  1183                         ((LambdaTranslationContext)localContext)
  1184                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
  1186                     localContext = localContext.prev;
  1189             if (context() != null && tree.type.tsym.owner.kind == MTH) {
  1190                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
  1191                 captureLocalClassDefs(tree.type.tsym, lambdaContext);
  1193             super.visitNewClass(tree);
  1195         //where
  1196             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
  1197                 JCClassDecl localCDef = localClassDefs.get(csym);
  1198                 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
  1199                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
  1200                         @Override
  1201                         void addFreeVars(ClassSymbol c) {
  1202                             captureLocalClassDefs(c, lambdaContext);
  1204                         @Override
  1205                         void visitSymbol(Symbol sym) {
  1206                             if (sym.kind == VAR &&
  1207                                     sym.owner.kind == MTH &&
  1208                                     ((VarSymbol)sym).getConstValue() == null) {
  1209                                 TranslationContext<?> localContext = context();
  1210                                 while (localContext != null) {
  1211                                     if (localContext.tree.getTag() == LAMBDA) {
  1212                                         JCTree block = capturedDecl(localContext.depth, sym);
  1213                                         if (block == null) break;
  1214                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
  1216                                     localContext = localContext.prev;
  1220                     };
  1221                     fvc.scan(localCDef);
  1225         @Override
  1226         public void visitReference(JCMemberReference tree) {
  1227             scan(tree.getQualifierExpression());
  1228             contextMap.put(tree, makeReferenceContext(tree));
  1231         @Override
  1232         public void visitSelect(JCFieldAccess tree) {
  1233             if (context() != null && lambdaSelectSymbolFilter(tree.sym)) {
  1234                 TranslationContext<?> localContext = context();
  1235                 while (localContext != null) {
  1236                     if (localContext.tree.hasTag(LAMBDA)) {
  1237                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
  1238                         if (clazz == null) break;
  1239                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
  1241                     localContext = localContext.prev;
  1243                 scan(tree.selected);
  1244             } else {
  1245                 super.visitSelect(tree);
  1249         @Override
  1250         public void visitVarDef(JCVariableDecl tree) {
  1251             TranslationContext<?> context = context();
  1252             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
  1253                     (LambdaTranslationContext)context :
  1254                     null;
  1255             if (ltc != null) {
  1256                 if (frameStack.head.tree.hasTag(LAMBDA)) {
  1257                     ltc.addSymbol(tree.sym, LOCAL_VAR);
  1259                 // Check for type variables (including as type arguments).
  1260                 // If they occur within class nested in a lambda, mark for erasure
  1261                 Type type = tree.sym.asType();
  1262                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
  1263                     ltc.addSymbol(tree.sym, TYPE_VAR);
  1267             List<Frame> prevStack = frameStack;
  1268             try {
  1269                 if (tree.sym.owner.kind == MTH) {
  1270                     frameStack.head.addLocal(tree.sym);
  1272                 frameStack = frameStack.prepend(new Frame(tree));
  1273                 super.visitVarDef(tree);
  1275             finally {
  1276                 frameStack = prevStack;
  1280         private Name lambdaName() {
  1281             return names.lambda.append(names.fromString("" + lambdaCount++));
  1284         /**
  1285          * For a serializable lambda, generate a name which maximizes name
  1286          * stability across deserialization.
  1287          * @param owner
  1288          * @return Name to use for the synthetic lambda method name
  1289          */
  1290         private Name serializedLambdaName(Symbol owner) {
  1291             StringBuilder buf = new StringBuilder();
  1292             buf.append(names.lambda);
  1293             // Append the name of the method enclosing the lambda.
  1294             String methodName = owner.name.toString();
  1295             if (methodName.equals("<clinit>"))
  1296                 methodName = "static";
  1297             else if (methodName.equals("<init>"))
  1298                 methodName = "new";
  1299             buf.append(methodName);
  1300             buf.append('$');
  1301             // Append a hash of the enclosing method signature to differentiate
  1302             // overloaded enclosing methods.  For lambdas enclosed in lambdas,
  1303             // the generated lambda method will not have type yet, but the
  1304             // enclosing method's name will have been generated with this same
  1305             // method, so it will be unique and never be overloaded.
  1306             Assert.check(owner.type != null || directlyEnclosingLambda() != null);
  1307             if (owner.type != null) {
  1308                 int methTypeHash = methodSig(owner.type).hashCode();
  1309                 buf.append(Integer.toHexString(methTypeHash));
  1311             buf.append('$');
  1312             // The above appended name components may not be unique, append a
  1313             // count based on the above name components.
  1314             String temp = buf.toString();
  1315             Integer count = serializableLambdaCounts.get(temp);
  1316             if (count == null) {
  1317                 count = 0;
  1319             buf.append(count++);
  1320             serializableLambdaCounts.put(temp, count);
  1321             return names.fromString(buf.toString());
  1324         /**
  1325          * Return a valid owner given the current declaration stack
  1326          * (required to skip synthetic lambda symbols)
  1327          */
  1328         private Symbol owner() {
  1329             return owner(false);
  1332         @SuppressWarnings("fallthrough")
  1333         private Symbol owner(boolean skipLambda) {
  1334             List<Frame> frameStack2 = frameStack;
  1335             while (frameStack2.nonEmpty()) {
  1336                 switch (frameStack2.head.tree.getTag()) {
  1337                     case VARDEF:
  1338                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
  1339                             frameStack2 = frameStack2.tail;
  1340                             break;
  1342                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
  1343                         return initSym(cdecl.sym,
  1344                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
  1345                     case BLOCK:
  1346                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
  1347                         return initSym(cdecl2.sym,
  1348                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
  1349                     case CLASSDEF:
  1350                         return ((JCClassDecl)frameStack2.head.tree).sym;
  1351                     case METHODDEF:
  1352                         return ((JCMethodDecl)frameStack2.head.tree).sym;
  1353                     case LAMBDA:
  1354                         if (!skipLambda)
  1355                             return ((LambdaTranslationContext)contextMap
  1356                                     .get(frameStack2.head.tree)).translatedSym;
  1357                     default:
  1358                         frameStack2 = frameStack2.tail;
  1361             Assert.error();
  1362             return null;
  1365         private Symbol initSym(ClassSymbol csym, long flags) {
  1366             boolean isStatic = (flags & STATIC) != 0;
  1367             if (isStatic) {
  1368                 //static clinits are generated in Gen - so we need to fake them
  1369                 Symbol clinit = clinits.get(csym);
  1370                 if (clinit == null) {
  1371                     clinit = makeSyntheticMethod(STATIC,
  1372                             names.clinit,
  1373                             new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
  1374                             csym);
  1375                     clinits.put(csym, clinit);
  1377                 return clinit;
  1378             } else {
  1379                 //get the first constructor and treat it as the instance init sym
  1380                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
  1381                     return s;
  1384             Assert.error("init not found");
  1385             return null;
  1388         private JCTree directlyEnclosingLambda() {
  1389             if (frameStack.isEmpty()) {
  1390                 return null;
  1392             List<Frame> frameStack2 = frameStack;
  1393             while (frameStack2.nonEmpty()) {
  1394                 switch (frameStack2.head.tree.getTag()) {
  1395                     case CLASSDEF:
  1396                     case METHODDEF:
  1397                         return null;
  1398                     case LAMBDA:
  1399                         return frameStack2.head.tree;
  1400                     default:
  1401                         frameStack2 = frameStack2.tail;
  1404             Assert.error();
  1405             return null;
  1408         private boolean inClassWithinLambda() {
  1409             if (frameStack.isEmpty()) {
  1410                 return false;
  1412             List<Frame> frameStack2 = frameStack;
  1413             boolean classFound = false;
  1414             while (frameStack2.nonEmpty()) {
  1415                 switch (frameStack2.head.tree.getTag()) {
  1416                     case LAMBDA:
  1417                         return classFound;
  1418                     case CLASSDEF:
  1419                         classFound = true;
  1420                         frameStack2 = frameStack2.tail;
  1421                         break;
  1422                     default:
  1423                         frameStack2 = frameStack2.tail;
  1426             // No lambda
  1427             return false;
  1430         /**
  1431          * Return the declaration corresponding to a symbol in the enclosing
  1432          * scope; the depth parameter is used to filter out symbols defined
  1433          * in nested scopes (which do not need to undergo capture).
  1434          */
  1435         private JCTree capturedDecl(int depth, Symbol sym) {
  1436             int currentDepth = frameStack.size() - 1;
  1437             for (Frame block : frameStack) {
  1438                 switch (block.tree.getTag()) {
  1439                     case CLASSDEF:
  1440                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
  1441                         if (sym.isMemberOf(clazz, types)) {
  1442                             return currentDepth > depth ? null : block.tree;
  1444                         break;
  1445                     case VARDEF:
  1446                         if (((JCVariableDecl)block.tree).sym == sym &&
  1447                                 sym.owner.kind == MTH) { //only locals are captured
  1448                             return currentDepth > depth ? null : block.tree;
  1450                         break;
  1451                     case BLOCK:
  1452                     case METHODDEF:
  1453                     case LAMBDA:
  1454                         if (block.locals != null && block.locals.contains(sym)) {
  1455                             return currentDepth > depth ? null : block.tree;
  1457                         break;
  1458                     default:
  1459                         Assert.error("bad decl kind " + block.tree.getTag());
  1461                 currentDepth--;
  1463             return null;
  1466         private TranslationContext<?> context() {
  1467             for (Frame frame : frameStack) {
  1468                 TranslationContext<?> context = contextMap.get(frame.tree);
  1469                 if (context != null) {
  1470                     return context;
  1473             return null;
  1476         /**
  1477          *  This is used to filter out those identifiers that needs to be adjusted
  1478          *  when translating away lambda expressions
  1479          */
  1480         private boolean lambdaIdentSymbolFilter(Symbol sym) {
  1481             return (sym.kind == VAR || sym.kind == MTH)
  1482                     && !sym.isStatic()
  1483                     && sym.name != names.init;
  1486         private boolean lambdaSelectSymbolFilter(Symbol sym) {
  1487             return (sym.kind == VAR || sym.kind == MTH) &&
  1488                         !sym.isStatic() &&
  1489                         (sym.name == names._this ||
  1490                         sym.name == names._super);
  1493         /**
  1494          * This is used to filter out those new class expressions that need to
  1495          * be qualified with an enclosing tree
  1496          */
  1497         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
  1498             if (context != null
  1499                     && tree.encl == null
  1500                     && tree.def == null
  1501                     && !tree.type.getEnclosingType().hasTag(NONE)) {
  1502                 Type encl = tree.type.getEnclosingType();
  1503                 Type current = context.owner.enclClass().type;
  1504                 while (!current.hasTag(NONE)) {
  1505                     if (current.tsym.isSubClass(encl.tsym, types)) {
  1506                         return true;
  1508                     current = current.getEnclosingType();
  1510                 return false;
  1511             } else {
  1512                 return false;
  1516         private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
  1517             return new LambdaTranslationContext(tree);
  1520         private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
  1521             return new ReferenceTranslationContext(tree);
  1524         private class Frame {
  1525             final JCTree tree;
  1526             List<Symbol> locals;
  1528             public Frame(JCTree tree) {
  1529                 this.tree = tree;
  1532             void addLocal(Symbol sym) {
  1533                 if (locals == null) {
  1534                     locals = List.nil();
  1536                 locals = locals.prepend(sym);
  1540         /**
  1541          * This class is used to store important information regarding translation of
  1542          * lambda expression/method references (see subclasses).
  1543          */
  1544         private abstract class TranslationContext<T extends JCFunctionalExpression> {
  1546             /** the underlying (untranslated) tree */
  1547             T tree;
  1549             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
  1550             Symbol owner;
  1552             /** the depth of this lambda expression in the frame stack */
  1553             int depth;
  1555             /** the enclosing translation context (set for nested lambdas/mref) */
  1556             TranslationContext<?> prev;
  1558             TranslationContext(T tree) {
  1559                 this.tree = tree;
  1560                 this.owner = owner();
  1561                 this.depth = frameStack.size() - 1;
  1562                 this.prev = context();
  1565             /** does this functional expression need to be created using alternate metafactory? */
  1566             boolean needsAltMetafactory() {
  1567                 return (tree.targets.length() > 1 ||
  1568                         isSerializable());
  1571             /** does this functional expression require serialization support? */
  1572             boolean isSerializable() {
  1573                 for (Symbol target : tree.targets) {
  1574                     if (types.asSuper(target.type, syms.serializableType.tsym) != null) {
  1575                         return true;
  1578                 return false;
  1582         /**
  1583          * This class retains all the useful information about a lambda expression;
  1584          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1585          * and the used by the main translation routines in order to adjust references
  1586          * to captured locals/members, etc.
  1587          */
  1588         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
  1590             /** variable in the enclosing context to which this lambda is assigned */
  1591             Symbol self;
  1593             /** map from original to translated lambda parameters */
  1594             Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
  1596             /** map from original to translated lambda locals */
  1597             Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
  1599             /** map from variables in enclosing scope to translated synthetic parameters */
  1600             Map<Symbol, Symbol> capturedLocals  = new LinkedHashMap<Symbol, Symbol>();
  1602             /** map from class symbols to translated synthetic parameters (for captured member access) */
  1603             Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
  1605             /** map from original to translated lambda locals */
  1606             Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
  1608             /** the synthetic symbol for the method hoisting the translated lambda */
  1609             Symbol translatedSym;
  1611             List<JCVariableDecl> syntheticParams;
  1613             LambdaTranslationContext(JCLambda tree) {
  1614                 super(tree);
  1615                 Frame frame = frameStack.head;
  1616                 if (frame.tree.hasTag(VARDEF)) {
  1617                     self = ((JCVariableDecl)frame.tree).sym;
  1619                 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
  1620                 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
  1623             /**
  1624              * Translate a symbol of a given kind into something suitable for the
  1625              * synthetic lambda body
  1626              */
  1627             Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
  1628                 switch (skind) {
  1629                     case CAPTURED_THIS:
  1630                         return sym;  // self represented
  1631                     case TYPE_VAR:
  1632                         // Just erase the type var
  1633                         return new VarSymbol(sym.flags(), name,
  1634                                 types.erasure(sym.type), sym.owner);
  1635                     case CAPTURED_VAR:
  1636                         return new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
  1637                             @Override
  1638                             public Symbol baseSymbol() {
  1639                                 //keep mapping with original captured symbol
  1640                                 return sym;
  1642                         };
  1643                     default:
  1644                         return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
  1648             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
  1649                 Map<Symbol, Symbol> transMap = null;
  1650                 Name preferredName;
  1651                 switch (skind) {
  1652                     case CAPTURED_THIS:
  1653                         transMap = capturedThis;
  1654                         preferredName = names.fromString("encl$" + capturedThis.size());
  1655                         break;
  1656                     case CAPTURED_VAR:
  1657                         transMap = capturedLocals;
  1658                         preferredName = names.fromString("cap$" + capturedLocals.size());
  1659                         break;
  1660                     case LOCAL_VAR:
  1661                         transMap = lambdaLocals;
  1662                         preferredName = sym.name;
  1663                         break;
  1664                     case PARAM:
  1665                         transMap = lambdaParams;
  1666                         preferredName = sym.name;
  1667                         break;
  1668                     case TYPE_VAR:
  1669                         transMap = typeVars;
  1670                         preferredName = sym.name;
  1671                         break;
  1672                     default: throw new AssertionError();
  1674                 if (!transMap.containsKey(sym)) {
  1675                     transMap.put(sym, translate(preferredName, sym, skind));
  1679             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind... skinds) {
  1680                 LinkedHashMap<Symbol, Symbol> translationMap = new LinkedHashMap<Symbol, Symbol>();
  1681                 for (LambdaSymbolKind skind : skinds) {
  1682                     switch (skind) {
  1683                         case CAPTURED_THIS:
  1684                             translationMap.putAll(capturedThis);
  1685                             break;
  1686                         case CAPTURED_VAR:
  1687                             translationMap.putAll(capturedLocals);
  1688                             break;
  1689                         case LOCAL_VAR:
  1690                             translationMap.putAll(lambdaLocals);
  1691                             break;
  1692                         case PARAM:
  1693                             translationMap.putAll(lambdaParams);
  1694                             break;
  1695                         case TYPE_VAR:
  1696                             translationMap.putAll(typeVars);
  1697                             break;
  1698                         default: throw new AssertionError();
  1701                 return translationMap;
  1704             /**
  1705              * The translatedSym is not complete/accurate until the analysis is
  1706              * finished.  Once the analysis is finished, the translatedSym is
  1707              * "completed" -- updated with type information, access modifiers,
  1708              * and full parameter list.
  1709              */
  1710             void complete() {
  1711                 if (syntheticParams != null) {
  1712                     return;
  1714                 boolean inInterface = translatedSym.owner.isInterface();
  1715                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
  1716                 boolean needInstance = thisReferenced || inInterface;
  1718                 // If instance access isn't needed, make it static
  1719                 // Interface methods much be public default methods, otherwise make it private
  1720                 translatedSym.flags_field = SYNTHETIC | (needInstance? 0 : STATIC) |
  1721                         (inInterface? PUBLIC | DEFAULT : PRIVATE);
  1723                 //compute synthetic params
  1724                 ListBuffer<JCVariableDecl> params = ListBuffer.lb();
  1726                 // The signature of the method is augmented with the following
  1727                 // synthetic parameters:
  1728                 //
  1729                 // 1) reference to enclosing contexts captured by the lambda expression
  1730                 // 2) enclosing locals captured by the lambda expression
  1731                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) {
  1732                     params.append(make.VarDef((VarSymbol) thisSym, null));
  1735                 syntheticParams = params.toList();
  1737                 //prepend synthetic args to translated lambda method signature
  1738                 translatedSym.type = types.createMethodTypeWithParameters(
  1739                         generatedLambdaSig(),
  1740                         TreeInfo.types(syntheticParams));
  1743             Type generatedLambdaSig() {
  1744                 return types.erasure(tree.descriptorType);
  1748         /**
  1749          * This class retains all the useful information about a method reference;
  1750          * the contents of this class are filled by the LambdaAnalyzer visitor,
  1751          * and the used by the main translation routines in order to adjust method
  1752          * references (i.e. in case a bridge is needed)
  1753          */
  1754         private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
  1756             final boolean isSuper;
  1757             final Symbol bridgeSym;
  1759             ReferenceTranslationContext(JCMemberReference tree) {
  1760                 super(tree);
  1761                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  1762                 this.bridgeSym = needsBridge()
  1763                         ? makeSyntheticMethod(isSuper ? 0 : STATIC,
  1764                                               lambdaName().append(names.fromString("$bridge")), null,
  1765                                               owner.enclClass())
  1766                         : null;
  1769             /**
  1770              * Get the opcode associated with this method reference
  1771              */
  1772             int referenceKind() {
  1773                 return LambdaToMethod.this.referenceKind(needsBridge() ? bridgeSym : tree.sym);
  1776             boolean needsVarArgsConversion() {
  1777                 return tree.varargsElement != null;
  1780             /**
  1781              * @return Is this an array operation like clone()
  1782              */
  1783             boolean isArrayOp() {
  1784                 return tree.sym.owner == syms.arrayClass;
  1787             boolean isPrivateConstructor() {
  1788                 //hack needed to workaround 292 bug (8005122)
  1789                 //when 292 issue is fixed we should simply remove this
  1790                 return tree.sym.name == names.init &&
  1791                         (tree.sym.flags() & PRIVATE) != 0;
  1794             boolean receiverAccessible() {
  1795                 //hack needed to workaround 292 bug (7087658)
  1796                 //when 292 issue is fixed we should remove this and change the backend
  1797                 //code to always generate a method handle to an accessible method
  1798                 return tree.ownerAccessible;
  1801             /**
  1802              * Does this reference needs a bridge (i.e. var args need to be
  1803              * expanded or "super" is used)
  1804              */
  1805             final boolean needsBridge() {
  1806                 return isSuper || needsVarArgsConversion() || isArrayOp() ||
  1807                         isPrivateConstructor() || !receiverAccessible();
  1810             Type generatedRefSig() {
  1811                 return types.erasure(tree.sym.type);
  1814             Type bridgedRefSig() {
  1815                 return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
  1819     // </editor-fold>
  1821     enum LambdaSymbolKind {
  1822         CAPTURED_VAR,
  1823         CAPTURED_THIS,
  1824         LOCAL_VAR,
  1825         PARAM,
  1826         TYPE_VAR;
  1829     /**
  1830      * ****************************************************************
  1831      * Signature Generation
  1832      * ****************************************************************
  1833      */
  1835     private String methodSig(Type type) {
  1836         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1837         sg.assembleSig(type);
  1838         return sg.toString();
  1841     private String classSig(Type type) {
  1842         L2MSignatureGenerator sg = new L2MSignatureGenerator();
  1843         sg.assembleClassSig(type);
  1844         return sg.toString();
  1847     /**
  1848      * Signature Generation
  1849      */
  1850     private class L2MSignatureGenerator extends Types.SignatureGenerator {
  1852         /**
  1853          * An output buffer for type signatures.
  1854          */
  1855         StringBuilder sb = new StringBuilder();
  1857         L2MSignatureGenerator() {
  1858             super(types);
  1861         @Override
  1862         protected void append(char ch) {
  1863             sb.append(ch);
  1866         @Override
  1867         protected void append(byte[] ba) {
  1868             sb.append(new String(ba));
  1871         @Override
  1872         protected void append(Name name) {
  1873             sb.append(name.toString());
  1876         @Override
  1877         public String toString() {
  1878             return sb.toString();

mercurial