--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri Mar 01 10:47:39 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Tue Mar 05 14:04:57 2013 +0000
@@ -163,6 +163,12 @@
*/
JCTree outermostMemberDef;
+ /** A map from local variable symbols to their translation (as per LambdaToMethod).
+ * This is required when a capturing local class is created from a lambda (in which
+ * case the captured symbols should be replaced with the translated lambda symbols).
+ */
+ Map<Symbol, Symbol> lambdaTranslationMap = null;
+
/** A navigator class for assembling a mapping from local class symbols
* to class definition trees.
* There is only one case; all other cases simply traverse down the tree.
@@ -206,10 +212,51 @@
Map<ClassSymbol,List<VarSymbol>> freevarCache;
/** A navigator class for collecting the free variables accessed
- * from a local class.
- * There is only one case; all other cases simply traverse down the tree.
+ * from a local class. There is only one case; all other cases simply
+ * traverse down the tree. This class doesn't deal with the specific
+ * of Lower - it's an abstract visitor that is meant to be reused in
+ * order to share the local variable capture logic.
*/
- class FreeVarCollector extends TreeScanner {
+ abstract class BasicFreeVarCollector extends TreeScanner {
+
+ /** Add all free variables of class c to fvs list
+ * unless they are already there.
+ */
+ abstract void addFreeVars(ClassSymbol c);
+
+ /** If tree refers to a variable in owner of local class, add it to
+ * free variables list.
+ */
+ public void visitIdent(JCIdent tree) {
+ visitSymbol(tree.sym);
+ }
+ // where
+ abstract void visitSymbol(Symbol _sym);
+
+ /** If tree refers to a class instance creation expression
+ * add all free variables of the freshly created class.
+ */
+ public void visitNewClass(JCNewClass tree) {
+ ClassSymbol c = (ClassSymbol)tree.constructor.owner;
+ addFreeVars(c);
+ super.visitNewClass(tree);
+ }
+
+ /** If tree refers to a superclass constructor call,
+ * add all free variables of the superclass.
+ */
+ public void visitApply(JCMethodInvocation tree) {
+ if (TreeInfo.name(tree.meth) == names._super) {
+ addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
+ }
+ super.visitApply(tree);
+ }
+ }
+
+ /**
+ * Lower-specific subclass of {@code BasicFreeVarCollector}.
+ */
+ class FreeVarCollector extends BasicFreeVarCollector {
/** The owner of the local class.
*/
@@ -238,10 +285,8 @@
fvs = fvs.prepend(v);
}
- /** Add all free variables of class c to fvs list
- * unless they are already there.
- */
- private void addFreeVars(ClassSymbol c) {
+ @Override
+ void addFreeVars(ClassSymbol c) {
List<VarSymbol> fvs = freevarCache.get(c);
if (fvs != null) {
for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
@@ -250,15 +295,8 @@
}
}
- /** If tree refers to a variable in owner of local class, add it to
- * free variables list.
- */
- public void visitIdent(JCIdent tree) {
- result = tree;
- visitSymbol(tree.sym);
- }
- // where
- private void visitSymbol(Symbol _sym) {
+ @Override
+ void visitSymbol(Symbol _sym) {
Symbol sym = _sym;
if (sym.kind == VAR || sym.kind == MTH) {
while (sym != null && sym.owner != owner)
@@ -281,7 +319,6 @@
*/
public void visitNewClass(JCNewClass tree) {
ClassSymbol c = (ClassSymbol)tree.constructor.owner;
- addFreeVars(c);
if (tree.encl == null &&
c.hasOuterInstance() &&
outerThisStack.head != null)
@@ -306,7 +343,6 @@
*/
public void visitApply(JCMethodInvocation tree) {
if (TreeInfo.name(tree.meth) == names._super) {
- addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
Symbol constructor = TreeInfo.symbol(tree.meth);
ClassSymbol c = (ClassSymbol)constructor.owner;
if (c.hasOuterInstance() &&
@@ -1171,6 +1207,14 @@
accessBase(tree.pos(), sym), sym).setType(tree.type);
}
}
+ } else if (sym.owner.kind == MTH && lambdaTranslationMap != null) {
+ //sym is a local variable - check the lambda translation map to
+ //see if sym has been translated to something else in the current
+ //scope (by LambdaToMethod)
+ Symbol translatedSym = lambdaTranslationMap.get(sym);
+ if (translatedSym != null) {
+ tree = make.at(tree.pos).Ident(translatedSym);
+ }
}
}
return tree;
@@ -2725,10 +2769,30 @@
outerThisStack = prevOuterThisStack;
} else {
- super.visitMethodDef(tree);
+ Map<Symbol, Symbol> prevLambdaTranslationMap =
+ lambdaTranslationMap;
+ try {
+ lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 &&
+ tree.sym.name.startsWith(names.lambda) ?
+ makeTranslationMap(tree) : null;
+ super.visitMethodDef(tree);
+ } finally {
+ lambdaTranslationMap = prevLambdaTranslationMap;
+ }
}
result = tree;
}
+ //where
+ private Map<Symbol, Symbol> makeTranslationMap(JCMethodDecl tree) {
+ Map<Symbol, Symbol> translationMap = new HashMap<Symbol,Symbol>();
+ for (JCVariableDecl vd : tree.params) {
+ Symbol p = vd.sym;
+ if (p != p.baseSymbol()) {
+ translationMap.put(p.baseSymbol(), p);
+ }
+ }
+ return translationMap;
+ }
public void visitAnnotatedType(JCAnnotatedType tree) {
// No need to retain type annotations any longer.