1.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Nov 25 08:30:52 2014 -0500 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Nov 25 13:37:34 2014 -0800 1.3 @@ -41,6 +41,7 @@ 1.4 import com.sun.tools.javac.code.Symtab; 1.5 import com.sun.tools.javac.code.Type; 1.6 import com.sun.tools.javac.code.Type.MethodType; 1.7 +import com.sun.tools.javac.code.Type.TypeVar; 1.8 import com.sun.tools.javac.code.Types; 1.9 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*; 1.10 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector; 1.11 @@ -61,6 +62,7 @@ 1.12 import static com.sun.tools.javac.code.Kinds.*; 1.13 import static com.sun.tools.javac.code.TypeTag.*; 1.14 import static com.sun.tools.javac.tree.JCTree.Tag.*; 1.15 +import javax.lang.model.type.TypeKind; 1.16 1.17 /** 1.18 * This pass desugars lambda expressions into static methods 1.19 @@ -761,49 +763,10 @@ 1.20 int prevPos = make.pos; 1.21 try { 1.22 make.at(tree); 1.23 - Type samDesc = localContext.bridgedRefSig(); 1.24 - List<Type> samPTypes = samDesc.getParameterTypes(); 1.25 - 1.26 - // an extra argument is prepended in the case where the member 1.27 - // reference is an unbound instance method reference (in which 1.28 - // case the receiver expression in passed. 1.29 - VarSymbol rcvr; 1.30 - switch (tree.kind) { 1.31 - case BOUND: 1.32 - rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); 1.33 - receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); 1.34 - break; 1.35 - case UNBOUND: 1.36 - rcvr = addParameter("rec$", samPTypes.head, false); 1.37 - samPTypes = samPTypes.tail; 1.38 - break; 1.39 - default: 1.40 - rcvr = null; 1.41 - break; 1.42 - } 1.43 - 1.44 - // generate the parameter list for the coverted member reference. 1.45 - // the signature will match the signature of the target sam descriptor 1.46 - 1.47 - List<Type> refPTypes = tree.sym.type.getParameterTypes(); 1.48 - int refSize = refPTypes.size(); 1.49 - int samSize = samPTypes.size(); 1.50 - // Last parameter to copy from referenced method 1.51 - int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize; 1.52 - 1.53 - List<Type> l = refPTypes; 1.54 - // Use parameter types of the referenced method, excluding final var args 1.55 - for (int i = 0; l.nonEmpty() && i < last; ++i) { 1.56 - addParameter("x$" + i, l.head, true); 1.57 - l = l.tail; 1.58 - } 1.59 - // Flatten out the var args 1.60 - for (int i = last; i < samSize; ++i) { 1.61 - addParameter("xva$" + i, tree.varargsElement, true); 1.62 - } 1.63 1.64 //body generation - this can be either a method call or a 1.65 //new instance creation expression, depending on the member reference kind 1.66 + VarSymbol rcvr = addParametersReturnReceiver(); 1.67 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) 1.68 ? expressionInvoke(rcvr) 1.69 : expressionNew(); 1.70 @@ -818,6 +781,78 @@ 1.71 } 1.72 } 1.73 1.74 + /** 1.75 + * Generate the parameter list for the converted member reference. 1.76 + * 1.77 + * @return The receiver variable symbol, if any 1.78 + */ 1.79 + VarSymbol addParametersReturnReceiver() { 1.80 + Type samDesc = localContext.bridgedRefSig(); 1.81 + List<Type> samPTypes = samDesc.getParameterTypes(); 1.82 + List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes(); 1.83 + 1.84 + // Determine the receiver, if any 1.85 + VarSymbol rcvr; 1.86 + switch (tree.kind) { 1.87 + case BOUND: 1.88 + // The receiver is explicit in the method reference 1.89 + rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); 1.90 + receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); 1.91 + break; 1.92 + case UNBOUND: 1.93 + // The receiver is the first parameter, extract it and 1.94 + // adjust the SAM and unerased type lists accordingly 1.95 + rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); 1.96 + samPTypes = samPTypes.tail; 1.97 + descPTypes = descPTypes.tail; 1.98 + break; 1.99 + default: 1.100 + rcvr = null; 1.101 + break; 1.102 + } 1.103 + List<Type> implPTypes = tree.sym.type.getParameterTypes(); 1.104 + int implSize = implPTypes.size(); 1.105 + int samSize = samPTypes.size(); 1.106 + // Last parameter to copy from referenced method, exclude final var args 1.107 + int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize; 1.108 + 1.109 + // Failsafe -- assure match-up 1.110 + boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); 1.111 + 1.112 + // Use parameter types of the implementation method unless the unerased 1.113 + // SAM parameter type is an intersection type, in that case use the 1.114 + // erased SAM parameter type so that the supertype relationship 1.115 + // the implementation method parameters is not obscured. 1.116 + // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes 1.117 + // are used as pointers to the current parameter type information 1.118 + // and are thus not usable afterwards. 1.119 + for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { 1.120 + // By default use the implementation method parmeter type 1.121 + Type parmType = implPTypes.head; 1.122 + // If the unerased parameter type is a type variable whose 1.123 + // bound is an intersection (eg. <T extends A & B>) then 1.124 + // use the SAM parameter type 1.125 + if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) { 1.126 + TypeVar tv = (TypeVar) descPTypes.head; 1.127 + if (tv.bound.getKind() == TypeKind.INTERSECTION) { 1.128 + parmType = samPTypes.head; 1.129 + } 1.130 + } 1.131 + addParameter("x$" + i, parmType, true); 1.132 + 1.133 + // Advance to the next parameter 1.134 + implPTypes = implPTypes.tail; 1.135 + samPTypes = samPTypes.tail; 1.136 + descPTypes = descPTypes.tail; 1.137 + } 1.138 + // Flatten out the var args 1.139 + for (int i = last; i < samSize; ++i) { 1.140 + addParameter("xva$" + i, tree.varargsElement, true); 1.141 + } 1.142 + 1.143 + return rcvr; 1.144 + } 1.145 + 1.146 JCExpression getReceiverExpression() { 1.147 return receiverExpression; 1.148 } 1.149 @@ -2067,11 +2102,35 @@ 1.150 } 1.151 1.152 /** 1.153 + * Erasure destroys the implementation parameter subtype 1.154 + * relationship for intersection types 1.155 + */ 1.156 + boolean interfaceParameterIsIntersectionType() { 1.157 + List<Type> tl = tree.getDescriptorType(types).getParameterTypes(); 1.158 + if (tree.kind == ReferenceKind.UNBOUND) { 1.159 + tl = tl.tail; 1.160 + } 1.161 + for (; tl.nonEmpty(); tl = tl.tail) { 1.162 + Type pt = tl.head; 1.163 + if (pt.getKind() == TypeKind.TYPEVAR) { 1.164 + TypeVar tv = (TypeVar) pt; 1.165 + if (tv.bound.getKind() == TypeKind.INTERSECTION) { 1.166 + return true; 1.167 + } 1.168 + } 1.169 + } 1.170 + return false; 1.171 + } 1.172 + 1.173 + /** 1.174 * Does this reference need to be converted to a lambda 1.175 * (i.e. var args need to be expanded or "super" is used) 1.176 */ 1.177 final boolean needsConversionToLambda() { 1.178 - return isSuper || needsVarArgsConversion() || isArrayOp() || 1.179 + return interfaceParameterIsIntersectionType() || 1.180 + isSuper || 1.181 + needsVarArgsConversion() || 1.182 + isArrayOp() || 1.183 isPrivateInOtherClass() || 1.184 !receiverAccessible() || 1.185 (tree.getMode() == ReferenceMode.NEW &&