|
29 | 29 | import java.util.stream.Collectors; |
30 | 30 |
|
31 | 31 | import com.sun.source.tree.LambdaExpressionTree.BodyKind; |
32 | | -import com.sun.source.tree.MemberReferenceTree.ReferenceMode; |
33 | 32 | import com.sun.tools.javac.code.*; |
34 | 33 | import com.sun.tools.javac.code.Kinds.KindSelector; |
35 | 34 | import com.sun.tools.javac.code.Scope.WriteableScope; |
|
39 | 38 | import com.sun.tools.javac.resources.CompilerProperties.Fragments; |
40 | 39 | import com.sun.tools.javac.resources.CompilerProperties.Notes; |
41 | 40 | import com.sun.tools.javac.tree.*; |
42 | | -import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; |
43 | 41 | import com.sun.tools.javac.util.*; |
44 | 42 | import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; |
45 | 43 | import com.sun.tools.javac.util.List; |
|
67 | 65 | import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT; |
68 | 66 | import com.sun.tools.javac.tree.JCTree.JCSwitchExpression; |
69 | 67 |
|
70 | | -import javax.lang.model.type.TypeKind; |
71 | | - |
72 | 68 | import static com.sun.tools.javac.tree.JCTree.Tag.*; |
73 | 69 |
|
74 | 70 | /** This pass translates away some syntactic sugar: inner classes, |
@@ -3903,337 +3899,6 @@ public void visitLambda(JCLambda tree) { |
3903 | 3899 | result = tree; |
3904 | 3900 | } |
3905 | 3901 |
|
3906 | | - @Override |
3907 | | - public void visitReference(JCMemberReference tree) { |
3908 | | - if (needsConversionToLambda(tree)) { |
3909 | | - // Convert to a lambda, and process as such |
3910 | | - MemberReferenceToLambda conv = new MemberReferenceToLambda(tree); |
3911 | | - result = translate(conv.lambda()); |
3912 | | - } else { |
3913 | | - super.visitReference(tree); |
3914 | | - } |
3915 | | - } |
3916 | | - // where |
3917 | | - boolean needsVarArgsConversion(JCMemberReference tree) { |
3918 | | - return tree.varargsElement != null; |
3919 | | - } |
3920 | | - |
3921 | | - /** |
3922 | | - * @return Is this an array operation like clone() |
3923 | | - */ |
3924 | | - boolean isArrayOp(JCMemberReference tree) { |
3925 | | - return tree.sym.owner == syms.arrayClass; |
3926 | | - } |
3927 | | - |
3928 | | - boolean receiverAccessible(JCMemberReference tree) { |
3929 | | - //hack needed to workaround 292 bug (7087658) |
3930 | | - //when 292 issue is fixed we should remove this and change the backend |
3931 | | - //code to always generate a method handle to an accessible method |
3932 | | - return tree.ownerAccessible; |
3933 | | - } |
3934 | | - |
3935 | | - /** |
3936 | | - * Erasure destroys the implementation parameter subtype |
3937 | | - * relationship for intersection types. |
3938 | | - * Have similar problems for union types too. |
3939 | | - */ |
3940 | | - boolean interfaceParameterIsIntersectionOrUnionType(JCMemberReference tree) { |
3941 | | - List<Type> tl = tree.getDescriptorType(types).getParameterTypes(); |
3942 | | - for (; tl.nonEmpty(); tl = tl.tail) { |
3943 | | - Type pt = tl.head; |
3944 | | - if (isIntersectionOrUnionType(pt)) |
3945 | | - return true; |
3946 | | - } |
3947 | | - return false; |
3948 | | - } |
3949 | | - |
3950 | | - boolean isIntersectionOrUnionType(Type t) { |
3951 | | - switch (t.getKind()) { |
3952 | | - case INTERSECTION: |
3953 | | - case UNION: |
3954 | | - return true; |
3955 | | - case TYPEVAR: |
3956 | | - TypeVar tv = (TypeVar) t; |
3957 | | - return isIntersectionOrUnionType(tv.getUpperBound()); |
3958 | | - } |
3959 | | - return false; |
3960 | | - } |
3961 | | - |
3962 | | - private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference, |
3963 | | - Symbol currentClass) { |
3964 | | - return ((targetReference.flags() & PROTECTED) != 0 && |
3965 | | - targetReference.packge() != currentClass.packge()); |
3966 | | - } |
3967 | | - |
3968 | | - /** |
3969 | | - * This method should be called only when target release <= 14 |
3970 | | - * where LambdaMetaFactory does not spin nestmate classes. |
3971 | | - * |
3972 | | - * This method should be removed when --release 14 is not supported. |
3973 | | - */ |
3974 | | - boolean isPrivateInOtherClass(JCMemberReference tree) { |
3975 | | - assert !target.runtimeUseNestAccess(); |
3976 | | - return (tree.sym.flags() & PRIVATE) != 0 && |
3977 | | - !types.isSameType( |
3978 | | - types.erasure(tree.sym.enclClass().asType()), |
3979 | | - types.erasure(currentClass.asType())); |
3980 | | - } |
3981 | | - |
3982 | | - /** |
3983 | | - * Does this reference need to be converted to a lambda |
3984 | | - * (i.e. var args need to be expanded or "super" is used) |
3985 | | - */ |
3986 | | - boolean needsConversionToLambda(JCMemberReference tree) { |
3987 | | - return interfaceParameterIsIntersectionOrUnionType(tree) || |
3988 | | - tree.hasKind(ReferenceKind.SUPER) || |
3989 | | - needsVarArgsConversion(tree) || |
3990 | | - isArrayOp(tree) || |
3991 | | - (!target.runtimeUseNestAccess() && isPrivateInOtherClass(tree)) || |
3992 | | - isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, currentClass) || |
3993 | | - !receiverAccessible(tree) || |
3994 | | - (tree.getMode() == ReferenceMode.NEW && |
3995 | | - tree.kind != ReferenceKind.ARRAY_CTOR && |
3996 | | - (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner())); |
3997 | | - } |
3998 | | - |
3999 | | - /** |
4000 | | - * Converts a method reference which cannot be used directly into a lambda |
4001 | | - */ |
4002 | | - private class MemberReferenceToLambda { |
4003 | | - |
4004 | | - private final JCMemberReference tree; |
4005 | | - private final ListBuffer<JCExpression> args = new ListBuffer<>(); |
4006 | | - private final ListBuffer<JCVariableDecl> params = new ListBuffer<>(); |
4007 | | - private final MethodSymbol owner = new MethodSymbol(0, names.empty, Type.noType, currentClass); |
4008 | | - |
4009 | | - private JCExpression receiverExpression = null; |
4010 | | - |
4011 | | - MemberReferenceToLambda(JCMemberReference tree) { |
4012 | | - this.tree = tree; |
4013 | | - } |
4014 | | - |
4015 | | - JCExpression lambda() { |
4016 | | - int prevPos = make.pos; |
4017 | | - try { |
4018 | | - make.at(tree); |
4019 | | - |
4020 | | - //body generation - this can be either a method call or a |
4021 | | - //new instance creation expression, depending on the member reference kind |
4022 | | - VarSymbol rcvr = addParametersReturnReceiver(); |
4023 | | - JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) |
4024 | | - ? expressionInvoke(rcvr) |
4025 | | - : expressionNew(); |
4026 | | - |
4027 | | - JCLambda slam = make.Lambda(params.toList(), expr); |
4028 | | - slam.target = tree.target; |
4029 | | - slam.type = tree.type; |
4030 | | - slam.pos = tree.pos; |
4031 | | - slam.wasMethodReference = true; |
4032 | | - if (receiverExpression != null) { |
4033 | | - // use a let expression so that the receiver expression is evaluated eagerly |
4034 | | - return make.at(tree.pos).LetExpr( |
4035 | | - make.VarDef(rcvr, translate(receiverExpression)), slam).setType(tree.type); |
4036 | | - } else { |
4037 | | - return slam; |
4038 | | - } |
4039 | | - } finally { |
4040 | | - make.at(prevPos); |
4041 | | - } |
4042 | | - } |
4043 | | - |
4044 | | - /** |
4045 | | - * Generate the parameter list for the converted member reference. |
4046 | | - * |
4047 | | - * @return The receiver variable symbol, if any |
4048 | | - */ |
4049 | | - VarSymbol addParametersReturnReceiver() { |
4050 | | - Type samDesc = types.erasure(types.findDescriptorSymbol(tree.target.tsym).type); |
4051 | | - List<Type> samPTypes = samDesc.getParameterTypes(); |
4052 | | - List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes(); |
4053 | | - |
4054 | | - // Determine the receiver, if any |
4055 | | - VarSymbol rcvr; |
4056 | | - switch (tree.kind) { |
4057 | | - case BOUND: |
4058 | | - // The receiver is explicit in the method reference |
4059 | | - rcvr = new VarSymbol(SYNTHETIC, names.fromString("rec$"), tree.getQualifierExpression().type, owner); |
4060 | | - rcvr.pos = tree.pos; |
4061 | | - receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); |
4062 | | - break; |
4063 | | - case UNBOUND: |
4064 | | - // The receiver is the first parameter, extract it and |
4065 | | - // adjust the SAM and unerased type lists accordingly |
4066 | | - rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); |
4067 | | - samPTypes = samPTypes.tail; |
4068 | | - descPTypes = descPTypes.tail; |
4069 | | - break; |
4070 | | - default: |
4071 | | - rcvr = null; |
4072 | | - break; |
4073 | | - } |
4074 | | - List<Type> implPTypes = tree.sym.type.getParameterTypes(); |
4075 | | - int implSize = implPTypes.size(); |
4076 | | - int samSize = samPTypes.size(); |
4077 | | - // Last parameter to copy from referenced method, exclude final var args |
4078 | | - int last = needsVarArgsConversion(tree) ? implSize - 1 : implSize; |
4079 | | - |
4080 | | - // Failsafe -- assure match-up |
4081 | | - boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); |
4082 | | - |
4083 | | - // Use parameter types of the implementation method unless the unerased |
4084 | | - // SAM parameter type is an intersection type, in that case use the |
4085 | | - // erased SAM parameter type so that the supertype relationship |
4086 | | - // the implementation method parameters is not obscured. |
4087 | | - // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes |
4088 | | - // are used as pointers to the current parameter type information |
4089 | | - // and are thus not usable afterwards. |
4090 | | - for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { |
4091 | | - // By default use the implementation method parameter type |
4092 | | - Type parmType = implPTypes.head; |
4093 | | - if (checkForIntersection) { |
4094 | | - if (descPTypes.head.getKind() == TypeKind.INTERSECTION) { |
4095 | | - parmType = samPTypes.head; |
4096 | | - } |
4097 | | - // If the unerased parameter type is a type variable whose |
4098 | | - // bound is an intersection (eg. <T extends A & B>) then |
4099 | | - // use the SAM parameter type |
4100 | | - if (descPTypes.head.getKind() == TypeKind.TYPEVAR) { |
4101 | | - TypeVar tv = (TypeVar) descPTypes.head; |
4102 | | - if (tv.getUpperBound().getKind() == TypeKind.INTERSECTION) { |
4103 | | - parmType = samPTypes.head; |
4104 | | - } |
4105 | | - } |
4106 | | - } |
4107 | | - addParameter("x$" + i, parmType, true); |
4108 | | - |
4109 | | - // Advance to the next parameter |
4110 | | - implPTypes = implPTypes.tail; |
4111 | | - samPTypes = samPTypes.tail; |
4112 | | - descPTypes = descPTypes.tail; |
4113 | | - } |
4114 | | - // Flatten out the var args |
4115 | | - for (int i = last; i < samSize; ++i) { |
4116 | | - addParameter("xva$" + i, tree.varargsElement, true); |
4117 | | - } |
4118 | | - |
4119 | | - return rcvr; |
4120 | | - } |
4121 | | - |
4122 | | - private JCExpression makeReceiver(VarSymbol rcvr) { |
4123 | | - if (rcvr == null) return null; |
4124 | | - JCExpression rcvrExpr = make.Ident(rcvr); |
4125 | | - boolean protAccess = |
4126 | | - isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, currentClass); |
4127 | | - Type rcvrType = tree.ownerAccessible && !protAccess ? tree.sym.enclClass().type |
4128 | | - : tree.expr.type; |
4129 | | - if (rcvrType == syms.arrayClass.type) { |
4130 | | - // Map the receiver type to the actually type, not just "array" |
4131 | | - rcvrType = tree.getQualifierExpression().type; |
4132 | | - } |
4133 | | - if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { |
4134 | | - rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); |
4135 | | - } |
4136 | | - return rcvrExpr; |
4137 | | - } |
4138 | | - |
4139 | | - /** |
4140 | | - * determine the receiver of the method call - the receiver can |
4141 | | - * be a type qualifier, the synthetic receiver parameter or 'super'. |
4142 | | - */ |
4143 | | - private JCExpression expressionInvoke(VarSymbol rcvr) { |
4144 | | - JCExpression qualifier = |
4145 | | - (rcvr != null) ? |
4146 | | - makeReceiver(rcvr) : |
4147 | | - tree.getQualifierExpression(); |
4148 | | - |
4149 | | - //create the qualifier expression |
4150 | | - JCFieldAccess select = make.Select(qualifier, tree.sym.name); |
4151 | | - select.sym = tree.sym; |
4152 | | - select.type = tree.sym.erasure(types); |
4153 | | - |
4154 | | - //create the method call expression |
4155 | | - JCExpression apply = make.Apply(List.nil(), select, |
4156 | | - convertArgs(tree.sym, args.toList(), tree.varargsElement)). |
4157 | | - setType(tree.sym.erasure(types).getReturnType()); |
4158 | | - |
4159 | | - apply = transTypes.coerce(attrEnv, apply, |
4160 | | - types.erasure(tree.referentType.getReturnType())); |
4161 | | - |
4162 | | - setVarargsIfNeeded(apply, tree.varargsElement); |
4163 | | - return apply; |
4164 | | - } |
4165 | | - |
4166 | | - /** |
4167 | | - * Lambda body to use for a 'new'. |
4168 | | - */ |
4169 | | - private JCExpression expressionNew() { |
4170 | | - if (tree.kind == ReferenceKind.ARRAY_CTOR) { |
4171 | | - //create the array creation expression |
4172 | | - JCNewArray newArr = make.NewArray( |
4173 | | - make.Type(types.elemtype(tree.getQualifierExpression().type)), |
4174 | | - List.of(make.Ident(params.first())), |
4175 | | - null); |
4176 | | - newArr.type = tree.getQualifierExpression().type; |
4177 | | - return newArr; |
4178 | | - } else { |
4179 | | - //create the instance creation expression |
4180 | | - //note that method reference syntax does not allow an explicit |
4181 | | - //enclosing class (so the enclosing class is null) |
4182 | | - // but this may need to be patched up later with the proxy for the outer this |
4183 | | - JCNewClass newClass = make.NewClass(null, |
4184 | | - List.nil(), |
4185 | | - make.Type(tree.getQualifierExpression().type), |
4186 | | - convertArgs(tree.sym, args.toList(), tree.varargsElement), |
4187 | | - null); |
4188 | | - newClass.constructor = tree.sym; |
4189 | | - newClass.constructorType = tree.sym.erasure(types); |
4190 | | - newClass.type = tree.getQualifierExpression().type; |
4191 | | - setVarargsIfNeeded(newClass, tree.varargsElement); |
4192 | | - return newClass; |
4193 | | - } |
4194 | | - } |
4195 | | - |
4196 | | - private VarSymbol addParameter(String name, Type p, boolean genArg) { |
4197 | | - VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); |
4198 | | - vsym.pos = tree.pos; |
4199 | | - params.append(make.VarDef(vsym, null)); |
4200 | | - if (genArg) { |
4201 | | - args.append(make.Ident(vsym)); |
4202 | | - } |
4203 | | - return vsym; |
4204 | | - } |
4205 | | - } |
4206 | | - |
4207 | | - /** |
4208 | | - * Convert method/constructor arguments by inserting appropriate cast |
4209 | | - * as required by type-erasure - this is needed when bridging a lambda/method |
4210 | | - * reference, as the bridged signature might require downcast to be compatible |
4211 | | - * with the generated signature. |
4212 | | - */ |
4213 | | - private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) { |
4214 | | - Assert.check(meth.kind == MTH); |
4215 | | - List<Type> formals = types.erasure(meth.type).getParameterTypes(); |
4216 | | - if (varargsElement != null) { |
4217 | | - Assert.check((meth.flags() & VARARGS) != 0); |
4218 | | - } |
4219 | | - return transTypes.translateArgs(args, formals, varargsElement, attrEnv); |
4220 | | - } |
4221 | | - |
4222 | | - /** |
4223 | | - * Set varargsElement field on a given tree (must be either a new class tree |
4224 | | - * or a method call tree) |
4225 | | - */ |
4226 | | - private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { |
4227 | | - if (varargsElement != null) { |
4228 | | - switch (tree.getTag()) { |
4229 | | - case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; |
4230 | | - case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; |
4231 | | - case TYPECAST: setVarargsIfNeeded(((JCTypeCast) tree).expr, varargsElement); break; |
4232 | | - default: throw new AssertionError(); |
4233 | | - } |
4234 | | - } |
4235 | | - } |
4236 | | - |
4237 | 3902 | public void visitSwitch(JCSwitch tree) { |
4238 | 3903 | List<JCCase> cases = tree.patternSwitch ? addDefaultIfNeeded(tree.patternSwitch, |
4239 | 3904 | tree.wasEnumSelector, |
|
0 commit comments