Thu, 21 Feb 2013 15:19:29 +0000
8008227: Mixing lambdas with anonymous classes leads to NPE thrown by compiler
Summary: Disentangle cyclic dependency between static-ness of synthetic lambda method and static-ness of classes nested within lambdas
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Wed Feb 20 15:47:14 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Thu Feb 21 15:19:29 2013 +0000 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -125,7 +125,8 @@ 1.11 MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, 1.12 List.<Type>nil(), syms.methodClass); 1.13 deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym); 1.14 - deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), syms.serializedLambdaType, deserMethodSym); 1.15 + deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), 1.16 + syms.serializedLambdaType, deserMethodSym); 1.17 } 1.18 1.19 private void addMethod(JCTree decl) { 1.20 @@ -738,7 +739,8 @@ 1.21 List<Type> refPTypes = tree.sym.type.getParameterTypes(); 1.22 int refSize = refPTypes.size(); 1.23 int samSize = samPTypes.size(); 1.24 - int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize; // Last parameter to copy from referenced method 1.25 + // Last parameter to copy from referenced method 1.26 + int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize; 1.27 1.28 List<Type> l = refPTypes; 1.29 // Use parameter types of the referenced method, excluding final var args 1.30 @@ -763,7 +765,8 @@ 1.31 null, 1.32 null); 1.33 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym; 1.34 - bridgeDecl.type = localContext.bridgeSym.type = types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList())); 1.35 + bridgeDecl.type = localContext.bridgeSym.type = 1.36 + types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList())); 1.37 1.38 //bridge method body generation - this can be either a method call or a 1.39 //new instance creation expression, depending on the member reference kind 1.40 @@ -803,7 +806,8 @@ 1.41 1.42 //create the method call expression 1.43 JCExpression apply = make.Apply(List.<JCExpression>nil(), select, 1.44 - convertArgs(tree.sym, args.toList(), tree.varargsElement)).setType(tree.sym.erasure(types).getReturnType()); 1.45 + convertArgs(tree.sym, args.toList(), tree.varargsElement)). 1.46 + setType(tree.sym.erasure(types).getReturnType()); 1.47 1.48 apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType()); 1.49 setVarargsIfNeeded(apply, tree.varargsElement); 1.50 @@ -817,7 +821,8 @@ 1.51 private JCExpression bridgeExpressionNew() { 1.52 if (tree.kind == ReferenceKind.ARRAY_CTOR) { 1.53 //create the array creation expression 1.54 - JCNewArray newArr = make.NewArray(make.Type(types.elemtype(tree.getQualifierExpression().type)), 1.55 + JCNewArray newArr = make.NewArray( 1.56 + make.Type(types.elemtype(tree.getQualifierExpression().type)), 1.57 List.of(make.Ident(params.first())), 1.58 null); 1.59 newArr.type = tree.getQualifierExpression().type; 1.60 @@ -872,7 +877,8 @@ 1.61 Type mtype = types.erasure(tree.descriptorType); 1.62 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); 1.63 List<Object> staticArgs = List.<Object>of( 1.64 - new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(tree.type.tsym), types), 1.65 + new Pool.MethodHandle(ClassFile.REF_invokeInterface, 1.66 + types.findDescriptorSymbol(tree.type.tsym), types), 1.67 new Pool.MethodHandle(refKind, refSym, types), 1.68 new MethodType(mtype.getParameterTypes(), 1.69 mtype.getReturnType(), 1.70 @@ -922,7 +928,8 @@ 1.71 * Generate an indy method call with given name, type and static bootstrap 1.72 * arguments types 1.73 */ 1.74 - private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) { 1.75 + private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, 1.76 + List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) { 1.77 int prevPos = make.pos; 1.78 try { 1.79 make.at(pos); 1.80 @@ -936,7 +943,9 @@ 1.81 DynamicMethodSymbol dynSym = 1.82 new DynamicMethodSymbol(names.lambda, 1.83 syms.noSymbol, 1.84 - bsm.isStatic() ? ClassFile.REF_invokeStatic : ClassFile.REF_invokeVirtual, 1.85 + bsm.isStatic() ? 1.86 + ClassFile.REF_invokeStatic : 1.87 + ClassFile.REF_invokeVirtual, 1.88 (MethodSymbol)bsm, 1.89 indyType, 1.90 staticArgs.toArray()); 1.91 @@ -1057,26 +1066,19 @@ 1.92 @Override 1.93 public void visitClassDef(JCClassDecl tree) { 1.94 List<Frame> prevStack = frameStack; 1.95 - Map<String, Integer> prevSerializableLambdaCount = serializableLambdaCounts; 1.96 + Map<String, Integer> prevSerializableLambdaCount = 1.97 + serializableLambdaCounts; 1.98 Map<ClassSymbol, Symbol> prevClinits = clinits; 1.99 try { 1.100 serializableLambdaCounts = new HashMap<String, Integer>(); 1.101 prevClinits = new HashMap<ClassSymbol, Symbol>(); 1.102 if (directlyEnclosingLambda() != null) { 1.103 tree.sym.owner = owner(); 1.104 - LambdaTranslationContext lambdaContext = (LambdaTranslationContext) contextMap.get(directlyEnclosingLambda()); 1.105 - Type encl = lambdaContext.enclosingType(); 1.106 - if (encl.hasTag(NONE)) { 1.107 - //if the translated lambda body occurs in a static context, 1.108 - //any class declaration within it must be made static 1.109 - //@@@TODO: What about nested classes within lambda? 1.110 - tree.sym.flags_field |= STATIC; 1.111 - ((ClassType) tree.sym.type).setEnclosingType(Type.noType); 1.112 - } else { 1.113 - //if the translated lambda body is in an instance context 1.114 - //the enclosing type of any class declaration within it 1.115 - //must be updated to point to the new enclosing type (if any) 1.116 - ((ClassType) tree.sym.type).setEnclosingType(encl); 1.117 + if (tree.sym.hasOuterInstance()) { 1.118 + //if a class is defined within a lambda, the lambda must capture 1.119 + //its enclosing instance (if any) 1.120 + ((LambdaTranslationContext) context()) 1.121 + .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); 1.122 } 1.123 } 1.124 frameStack = frameStack.prepend(new Frame(tree)); 1.125 @@ -1087,11 +1089,6 @@ 1.126 serializableLambdaCounts = prevSerializableLambdaCount; 1.127 clinits = prevClinits; 1.128 } 1.129 - if (!tree.sym.isStatic() && directlyEnclosingLambda() != null) { 1.130 - // Any (non-static) class defined within a lambda is an implicit 'this' reference 1.131 - // because its constructor will reference the enclosing class 1.132 - ((LambdaTranslationContext) context()).addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); 1.133 - } 1.134 } 1.135 1.136 @Override 1.137 @@ -1105,7 +1102,8 @@ 1.138 if (localContext.tree.getTag() == LAMBDA) { 1.139 JCTree block = capturedDecl(localContext.depth, tree.sym); 1.140 if (block == null) break; 1.141 - ((LambdaTranslationContext)localContext).addSymbol(tree.sym, CAPTURED_VAR); 1.142 + ((LambdaTranslationContext)localContext) 1.143 + .addSymbol(tree.sym, CAPTURED_VAR); 1.144 } 1.145 localContext = localContext.prev; 1.146 } 1.147 @@ -1118,7 +1116,8 @@ 1.148 switch (block.getTag()) { 1.149 case CLASSDEF: 1.150 JCClassDecl cdecl = (JCClassDecl)block; 1.151 - ((LambdaTranslationContext)localContext).addSymbol(cdecl.sym, CAPTURED_THIS); 1.152 + ((LambdaTranslationContext)localContext) 1.153 + .addSymbol(cdecl.sym, CAPTURED_THIS); 1.154 break; 1.155 default: 1.156 Assert.error("bad block kind"); 1.157 @@ -1165,7 +1164,8 @@ 1.158 @Override 1.159 public void visitNewClass(JCNewClass tree) { 1.160 if (lambdaNewClassFilter(context(), tree)) { 1.161 - ((LambdaTranslationContext) context()).addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS); 1.162 + ((LambdaTranslationContext) context()) 1.163 + .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS); 1.164 } 1.165 super.visitNewClass(tree); 1.166 } 1.167 @@ -1278,7 +1278,8 @@ 1.168 return ((JCMethodDecl)frameStack2.head.tree).sym; 1.169 case LAMBDA: 1.170 if (!skipLambda) 1.171 - return ((LambdaTranslationContext)contextMap.get(frameStack2.head.tree)).translatedSym; 1.172 + return ((LambdaTranslationContext)contextMap 1.173 + .get(frameStack2.head.tree)).translatedSym; 1.174 default: 1.175 frameStack2 = frameStack2.tail; 1.176 } 1.177 @@ -1555,7 +1556,8 @@ 1.178 return sym; // self represented 1.179 case TYPE_VAR: 1.180 // Just erase the type var 1.181 - return new VarSymbol(sym.flags(), names.fromString(name), types.erasure(sym.type), sym.owner); 1.182 + return new VarSymbol(sym.flags(), names.fromString(name), 1.183 + types.erasure(sym.type), sym.owner); 1.184 default: 1.185 return makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); 1.186 } 1.187 @@ -1633,7 +1635,8 @@ 1.188 1.189 // If instance access isn't needed, make it static 1.190 // Interface methods much be public default methods, otherwise make it private 1.191 - translatedSym.flags_field = SYNTHETIC | (needInstance? 0 : STATIC) | (inInterface? PUBLIC | DEFAULT : PRIVATE); 1.192 + translatedSym.flags_field = SYNTHETIC | (needInstance? 0 : STATIC) | 1.193 + (inInterface? PUBLIC | DEFAULT : PRIVATE); 1.194 1.195 //compute synthetic params 1.196 ListBuffer<JCVariableDecl> params = ListBuffer.lb(); 1.197 @@ -1655,12 +1658,6 @@ 1.198 TreeInfo.types(syntheticParams)); 1.199 } 1.200 1.201 - Type enclosingType() { 1.202 - return owner.isStatic() ? 1.203 - Type.noType : 1.204 - owner.enclClass().type; 1.205 - } 1.206 - 1.207 Type generatedLambdaSig() { 1.208 return types.erasure(tree.descriptorType); 1.209 }
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/tools/javac/lambda/LambdaConv27.java Thu Feb 21 15:19:29 2013 +0000 2.3 @@ -0,0 +1,40 @@ 2.4 +/* 2.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + */ 2.26 + 2.27 +/* 2.28 + * @test 2.29 + * @bug 8008227 2.30 + * @summary Mixing lambdas with anonymous classes leads to NPE thrown by compiler 2.31 + * @run main LambdaConv27 2.32 + */ 2.33 +public class LambdaConv27 { 2.34 + 2.35 + public static void main(String[] args) { 2.36 + SAM s = ()-> { SAM s2 = ()->{ new Object() { }; }; s2.m(); }; 2.37 + s.m(); 2.38 + } 2.39 + 2.40 + interface SAM { 2.41 + void m(); 2.42 + } 2.43 +}