--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Dec 18 19:15:58 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Dec 18 19:22:58 2013 +0000
@@ -2590,15 +2590,61 @@
}
}
+ /* Map to hold 'fake' clinit methods. If a lambda is used to initialize a
+ * static field and that lambda has type annotations, these annotations will
+ * also be stored at these fake clinit methods.
+ *
+ * LambdaToMethod also use fake clinit methods so they can be reused.
+ * Also as LTM is a phase subsequent to attribution, the methods from
+ * clinits can be safely removed by LTM to save memory.
+ */
+ private Map<ClassSymbol, MethodSymbol> clinits = new HashMap<>();
+
+ public MethodSymbol removeClinit(ClassSymbol sym) {
+ return clinits.remove(sym);
+ }
+
+ /* This method returns an environment to be used to attribute a lambda
+ * expression.
+ *
+ * The owner of this environment is a method symbol. If the current owner
+ * is not a method, for example if the lambda is used to initialize
+ * a field, then if the field is:
+ *
+ * - an instance field, we use the first constructor.
+ * - a static field, we create a fake clinit method.
+ */
private Env<AttrContext> lambdaEnv(JCLambda that, Env<AttrContext> env) {
Env<AttrContext> lambdaEnv;
Symbol owner = env.info.scope.owner;
if (owner.kind == VAR && owner.owner.kind == TYP) {
//field initializer
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dupUnshared()));
- lambdaEnv.info.scope.owner =
- new MethodSymbol((owner.flags() & STATIC) | BLOCK, names.empty, null,
- env.info.scope.owner);
+ ClassSymbol enclClass = owner.enclClass();
+ /* if the field isn't static, then we can get the first constructor
+ * and use it as the owner of the environment. This is what
+ * LTM code is doing to look for type annotations so we are fine.
+ */
+ if ((owner.flags() & STATIC) == 0) {
+ for (Symbol s : enclClass.members_field.getElementsByName(names.init)) {
+ lambdaEnv.info.scope.owner = s;
+ break;
+ }
+ } else {
+ /* if the field is static then we need to create a fake clinit
+ * method, this method can later be reused by LTM.
+ */
+ MethodSymbol clinit = clinits.get(enclClass);
+ if (clinit == null) {
+ Type clinitType = new MethodType(List.<Type>nil(),
+ syms.voidType, List.<Type>nil(), syms.methodClass);
+ clinit = new MethodSymbol(STATIC | SYNTHETIC | PRIVATE,
+ names.clinit, clinitType, enclClass);
+ clinit.params = List.<VarSymbol>nil();
+ clinits.put(enclClass, clinit);
+ }
+ lambdaEnv.info.scope.owner = clinit;
+ }
} else {
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
}