1 /*
2 * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.comp;
27
28
29 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
30 import com.sun.tools.javac.code.*;
31 import com.sun.tools.javac.code.Attribute.TypeCompound;
32 import com.sun.tools.javac.code.Symbol.*;
33 import com.sun.tools.javac.code.Type.TypeVar;
34 import com.sun.tools.javac.jvm.Target;
35 import com.sun.tools.javac.tree.*;
36 import com.sun.tools.javac.tree.JCTree.*;
37 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
38 import com.sun.tools.javac.util.*;
39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
40 import com.sun.tools.javac.util.List;
41
42 import static com.sun.tools.javac.code.Flags.*;
43 import static com.sun.tools.javac.code.Kinds.Kind.*;
44 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
45 import static com.sun.tools.javac.code.TypeTag.CLASS;
46 import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
47 import static com.sun.tools.javac.code.TypeTag.VOID;
48 import static com.sun.tools.javac.comp.CompileStates.CompileState;
49 import com.sun.tools.javac.tree.JCTree.JCBreak;
50
51 /** This pass translates Generic Java to conventional Java.
52 *
53 * <p><b>This is NOT part of any supported API.
54 * If you write code that depends on this, you do so at your own risk.
55 * This code and its internal interfaces are subject to change or
56 * deletion without notice.</b>
57 */
58 public class TransTypes extends TreeTranslator {
59 /** The context key for the TransTypes phase. */
60 protected static final Context.Key<TransTypes> transTypesKey = new Context.Key<>();
61
62 /** Get the instance for this context. */
63 public static TransTypes instance(Context context) {
64 TransTypes instance = context.get(transTypesKey);
65 if (instance == null)
66 instance = new TransTypes(context);
67 return instance;
68 }
69
70 private Names names;
71 private Log log;
72 private Symtab syms;
73 private TreeMaker make;
74 private Enter enter;
75 private Types types;
76 private Annotate annotate;
77 private Attr attr;
78 private final Resolve resolve;
79 private final CompileStates compileStates;
80 private final Target target;
81
82 @SuppressWarnings("this-escape")
83 protected TransTypes(Context context) {
84 context.put(transTypesKey, this);
85 compileStates = CompileStates.instance(context);
86 names = Names.instance(context);
87 log = Log.instance(context);
88 syms = Symtab.instance(context);
89 enter = Enter.instance(context);
90 types = Types.instance(context);
91 make = TreeMaker.instance(context);
92 resolve = Resolve.instance(context);
93 annotate = Annotate.instance(context);
94 attr = Attr.instance(context);
95 target = Target.instance(context);
96 }
97
98 /** Construct an attributed tree for a cast of expression to target type,
99 * unless it already has precisely that type.
100 * @param tree The expression tree.
101 * @param target The target type.
102 */
103 JCExpression cast(JCExpression tree, Type target) {
104 int oldpos = make.pos;
105 make.at(tree.pos);
106 if (!types.isSameType(tree.type, target)) {
107 if (!resolve.isAccessible(env, target.tsym))
108 resolve.logAccessErrorInternal(env, tree, target);
109 tree = make.TypeCast(make.Type(target), tree).setType(target);
110 }
111 make.pos = oldpos;
112 return tree;
113 }
114
115 /** Construct an attributed tree to coerce an expression to some erased
116 * target type, unless the expression is already assignable to that type.
117 * If target type is a constant type, use its base type instead.
118 * @param tree The expression tree.
119 * @param target The target type.
120 */
121 public JCExpression coerce(Env<AttrContext> env, JCExpression tree, Type target) {
122 Env<AttrContext> prevEnv = this.env;
123 try {
124 this.env = env;
125 return coerce(tree, target);
126 }
127 finally {
128 this.env = prevEnv;
129 }
130 }
131 JCExpression coerce(JCExpression tree, Type target) {
132 Type btarget = target.baseType();
133 if (tree.type.isPrimitive() == target.isPrimitive()) {
134 return types.isAssignable(tree.type, btarget, types.noWarnings)
135 ? tree
136 : cast(tree, btarget);
137 }
138 return tree;
139 }
140
141 /** Given an erased reference type, assume this type as the tree's type.
142 * Then, coerce to some given target type unless target type is null.
143 * This operation is used in situations like the following:
144 *
145 * <pre>{@code
146 * class Cell<A> { A value; }
147 * ...
148 * Cell<Integer> cell;
149 * Integer x = cell.value;
150 * }</pre>
151 *
152 * Since the erasure of Cell.value is Object, but the type
153 * of cell.value in the assignment is Integer, we need to
154 * adjust the original type of cell.value to Object, and insert
155 * a cast to Integer. That is, the last assignment becomes:
156 *
157 * <pre>{@code
158 * Integer x = (Integer)cell.value;
159 * }</pre>
160 *
161 * @param tree The expression tree whose type might need adjustment.
162 * @param erasedType The expression's type after erasure.
163 * @param target The target type, which is usually the erasure of the
164 * expression's original type.
165 */
166 JCExpression retype(JCExpression tree, Type erasedType, Type target) {
167 // System.err.println("retype " + tree + " to " + erasedType);//DEBUG
168 if (!erasedType.isPrimitive()) {
169 if (target != null && target.isPrimitive()) {
170 target = erasure(tree.type);
171 }
172 tree.type = erasedType;
173 if (target != null) {
174 return coerce(tree, target);
175 }
176 }
177 return tree;
178 }
179
180 /** Translate method argument list, casting each argument
181 * to its corresponding type in a list of target types.
182 * @param _args The method argument list.
183 * @param parameters The list of target types.
184 * @param varargsElement The erasure of the varargs element type,
185 * or null if translating a non-varargs invocation
186 */
187 <T extends JCTree> List<T> translateArgs(List<T> _args,
188 List<Type> parameters,
189 Type varargsElement) {
190 if (parameters.isEmpty()) return _args;
191 List<T> args = _args;
192 while (parameters.tail.nonEmpty()) {
193 args.head = translate(args.head, parameters.head);
194 args = args.tail;
195 parameters = parameters.tail;
196 }
197 Type parameter = parameters.head;
198 Assert.check(varargsElement != null || args.length() == 1);
199 if (varargsElement != null) {
200 while (args.nonEmpty()) {
201 args.head = translate(args.head, varargsElement);
202 args = args.tail;
203 }
204 } else {
205 args.head = translate(args.head, parameter);
206 }
207 return _args;
208 }
209
210 public <T extends JCTree> List<T> translateArgs(List<T> _args,
211 List<Type> parameters,
212 Type varargsElement,
213 Env<AttrContext> localEnv) {
214 Env<AttrContext> prevEnv = env;
215 try {
216 env = localEnv;
217 return translateArgs(_args, parameters, varargsElement);
218 }
219 finally {
220 env = prevEnv;
221 }
222 }
223
224 /** Add a bridge definition and enter corresponding method symbol in
225 * local scope of origin.
226 *
227 * @param pos The source code position to be used for the definition.
228 * @param meth The method for which a bridge needs to be added
229 * @param impl That method's implementation (possibly the method itself)
230 * @param origin The class to which the bridge will be added
231 * @param bridges The list buffer to which the bridge will be added
232 */
233 void addBridge(DiagnosticPosition pos,
234 MethodSymbol meth,
235 MethodSymbol impl,
236 ClassSymbol origin,
237 ListBuffer<JCTree> bridges) {
238 make.at(pos);
239 Type implTypeErasure = erasure(impl.type);
240
241 // Create a bridge method symbol and a bridge definition without a body.
242 Type bridgeType = meth.erasure(types);
243 long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE |
244 (origin.isInterface() ? DEFAULT : 0);
245 MethodSymbol bridge = new MethodSymbol(flags,
246 meth.name,
247 bridgeType,
248 origin);
249 /* once JDK-6996415 is solved it should be checked if this approach can
250 * be applied to method addOverrideBridgesIfNeeded
251 */
252 bridge.params = createBridgeParams(impl, bridge, bridgeType);
253 bridge.setAttributes(impl);
254
255 JCMethodDecl md = make.MethodDef(bridge, null);
256
257 // The bridge calls this.impl(..), if we have an implementation
258 // in the current class, super.impl(...) otherwise.
259 JCExpression receiver = (impl.owner == origin)
260 ? make.This(origin.erasure(types))
261 : make.Super(types.supertype(origin.type).tsym.erasure(types), origin);
262
263 // The type returned from the original method.
264 Type calltype = implTypeErasure.getReturnType();
265
266 // Construct a call of this.impl(params), or super.impl(params),
267 // casting params and possibly results as needed.
268 JCExpression call =
269 make.Apply(
270 null,
271 make.Select(receiver, impl).setType(calltype),
272 translateArgs(make.Idents(md.params), implTypeErasure.getParameterTypes(), null))
273 .setType(calltype);
274 JCStatement stat = (implTypeErasure.getReturnType().hasTag(VOID))
275 ? make.Exec(call)
276 : make.Return(coerce(call, bridgeType.getReturnType()));
277 md.body = make.Block(0, List.of(stat));
278
279 // Add bridge to `bridges' buffer
280 bridges.append(md);
281
282 // Add bridge to scope of enclosing class and keep track of the bridge span.
283 origin.members().enter(bridge);
284 }
285
286 private List<VarSymbol> createBridgeParams(MethodSymbol impl, MethodSymbol bridge,
287 Type bridgeType) {
288 List<VarSymbol> bridgeParams = null;
289 if (impl.params != null) {
290 bridgeParams = List.nil();
291 List<VarSymbol> implParams = impl.params;
292 Type.MethodType mType = (Type.MethodType)bridgeType;
293 List<Type> argTypes = mType.argtypes;
294 while (implParams.nonEmpty() && argTypes.nonEmpty()) {
295 VarSymbol param = new VarSymbol(implParams.head.flags() | SYNTHETIC | PARAMETER,
296 implParams.head.name, argTypes.head, bridge);
297 param.setAttributes(implParams.head);
298 bridgeParams = bridgeParams.append(param);
299 implParams = implParams.tail;
300 argTypes = argTypes.tail;
301 }
302 }
303 return bridgeParams;
304 }
305
306 /** Add bridge if given symbol is a non-private, non-static member
307 * of the given class, which is either defined in the class or non-final
308 * inherited, and one of the two following conditions holds:
309 * 1. The method's type changes in the given class, as compared to the
310 * class where the symbol was defined, (in this case
311 * we have extended a parameterized class with non-trivial parameters).
312 * 2. The method has an implementation with a different erased return type.
313 * (in this case we have used co-variant returns).
314 * If a bridge already exists in some other class, no new bridge is added.
315 * Instead, it is checked that the bridge symbol overrides the method symbol.
316 * (Spec ???).
317 * todo: what about bridges for privates???
318 *
319 * @param pos The source code position to be used for the definition.
320 * @param sym The symbol for which a bridge might have to be added.
321 * @param origin The class in which the bridge would go.
322 * @param bridges The list buffer to which the bridge would be added.
323 */
324 void addBridgeIfNeeded(DiagnosticPosition pos,
325 Symbol sym,
326 ClassSymbol origin,
327 ListBuffer<JCTree> bridges) {
328 if (sym.kind == MTH &&
329 sym.name != names.init &&
330 (sym.flags() & (PRIVATE | STATIC)) == 0 &&
331 (sym.flags() & SYNTHETIC) != SYNTHETIC &&
332 sym.isMemberOf(origin, types)) {
333 MethodSymbol meth = (MethodSymbol)sym;
334 MethodSymbol bridge = meth.binaryImplementation(origin, types);
335 MethodSymbol impl = meth.implementation(origin, types, true);
336 if (bridge == null ||
337 bridge == meth ||
338 (impl != null && !bridge.owner.isSubClass(impl.owner, types))) {
339 // No bridge was added yet.
340 if (impl != null && bridge != impl && isBridgeNeeded(meth, impl, origin.type)) {
341 addBridge(pos, meth, impl, origin, bridges);
342 } else if (impl == meth
343 && impl.owner != origin
344 && (impl.flags() & FINAL) == 0
345 && (meth.flags() & (ABSTRACT|PUBLIC)) == PUBLIC
346 && (origin.flags() & PUBLIC) > (impl.owner.flags() & PUBLIC)) {
347 // this is to work around a horrible but permanent
348 // reflection design error.
349 addBridge(pos, meth, impl, origin, bridges);
350 }
351 }
352 }
353 }
354 // where
355
356 /**
357 * @param method The symbol for which a bridge might have to be added
358 * @param impl The implementation of method
359 * @param dest The type in which the bridge would go
360 */
361 private boolean isBridgeNeeded(MethodSymbol method,
362 MethodSymbol impl,
363 Type dest) {
364 if (impl != method) {
365 // If either method or impl have different erasures as
366 // members of dest, a bridge is needed.
367 Type method_erasure = method.erasure(types);
368 if (!isSameMemberWhenErased(dest, method, method_erasure))
369 return true;
370 Type impl_erasure = impl.erasure(types);
371 if (!isSameMemberWhenErased(dest, impl, impl_erasure))
372 return true;
373
374 /* Bottom line: A bridge is needed if the erasure of the implementation
375 is different from that of the method that it overrides.
376 */
377 return !types.isSameType(impl_erasure, method_erasure);
378 } else {
379 // method and impl are the same...
380 if ((method.flags() & ABSTRACT) != 0) {
381 // ...and abstract so a bridge is not needed.
382 // Concrete subclasses will bridge as needed.
383 return false;
384 }
385
386 // The erasure of the return type is always the same
387 // for the same symbol. Reducing the three tests in
388 // the other branch to just one:
389 return !isSameMemberWhenErased(dest, method, method.erasure(types));
390 }
391 }
392 /**
393 * Lookup the method as a member of the type. Compare the
394 * erasures.
395 * @param type the class where to look for the method
396 * @param method the method to look for in class
397 * @param erasure the erasure of method
398 */
399 private boolean isSameMemberWhenErased(Type type,
400 MethodSymbol method,
401 Type erasure) {
402 return types.isSameType(erasure(types.memberType(type, method)),
403 erasure);
404 }
405
406 void addBridges(DiagnosticPosition pos,
407 TypeSymbol i,
408 ClassSymbol origin,
409 ListBuffer<JCTree> bridges) {
410 for (Symbol sym : i.members().getSymbols(NON_RECURSIVE))
411 addBridgeIfNeeded(pos, sym, origin, bridges);
412 for (List<Type> l = types.interfaces(i.type); l.nonEmpty(); l = l.tail)
413 addBridges(pos, l.head.tsym, origin, bridges);
414 }
415
416 /** Add all necessary bridges to some class appending them to list buffer.
417 * @param pos The source code position to be used for the bridges.
418 * @param origin The class in which the bridges go.
419 * @param bridges The list buffer to which the bridges are added.
420 */
421 void addBridges(DiagnosticPosition pos, ClassSymbol origin, ListBuffer<JCTree> bridges) {
422 Type st = types.supertype(origin.type);
423 while (st.hasTag(CLASS)) {
424 // if (isSpecialization(st))
425 addBridges(pos, st.tsym, origin, bridges);
426 st = types.supertype(st);
427 }
428 for (List<Type> l = types.interfaces(origin.type); l.nonEmpty(); l = l.tail)
429 // if (isSpecialization(l.head))
430 addBridges(pos, l.head.tsym, origin, bridges);
431 }
432
433 /* ************************************************************************
434 * Visitor methods
435 *************************************************************************/
436
437 /** Visitor argument: proto-type.
438 */
439 private Type pt;
440
441 /** Visitor method: perform a type translation on tree.
442 */
443 public <T extends JCTree> T translate(T tree, Type pt) {
444 Type prevPt = this.pt;
445 try {
446 this.pt = pt;
447 return translate(tree);
448 } finally {
449 this.pt = prevPt;
450 }
451 }
452
453 /** Visitor method: perform a type translation on list of trees.
454 */
455 public <T extends JCTree> List<T> translate(List<T> trees, Type pt) {
456 Type prevPt = this.pt;
457 List<T> res;
458 try {
459 this.pt = pt;
460 res = translate(trees);
461 } finally {
462 this.pt = prevPt;
463 }
464 return res;
465 }
466
467 public void visitClassDef(JCClassDecl tree) {
468 translateClass(tree.sym);
469 result = tree;
470 }
471
472 Type returnType = null;
473 public void visitMethodDef(JCMethodDecl tree) {
474 Type prevRetType = returnType;
475 try {
476 returnType = erasure(tree.type).getReturnType();
477 tree.restype = translate(tree.restype, null);
478 tree.typarams = List.nil();
479 tree.params = translateVarDefs(tree.params);
480 tree.recvparam = translate(tree.recvparam, null);
481 tree.thrown = translate(tree.thrown, null);
482 tree.body = translate(tree.body, tree.sym.erasure(types).getReturnType());
483 tree.type = erasure(tree.type);
484 result = tree;
485 } finally {
486 returnType = prevRetType;
487 }
488 }
489
490 public void visitVarDef(JCVariableDecl tree) {
491 tree.vartype = translate(tree.vartype, null);
492 tree.init = translate(tree.init, tree.sym.erasure(types));
493 tree.type = erasure(tree.type);
494 result = tree;
495 }
496
497 public void visitDoLoop(JCDoWhileLoop tree) {
498 tree.body = translate(tree.body);
499 tree.cond = translate(tree.cond, syms.booleanType);
500 result = tree;
501 }
502
503 public void visitWhileLoop(JCWhileLoop tree) {
504 tree.cond = translate(tree.cond, syms.booleanType);
505 tree.body = translate(tree.body);
506 result = tree;
507 }
508
509 public void visitForLoop(JCForLoop tree) {
510 tree.init = translate(tree.init, null);
511 if (tree.cond != null)
512 tree.cond = translate(tree.cond, syms.booleanType);
513 tree.step = translate(tree.step, null);
514 tree.body = translate(tree.body);
515 result = tree;
516 }
517
518 public void visitForeachLoop(JCEnhancedForLoop tree) {
519 tree.var = translate(tree.var, null);
520 Type iterableType = tree.expr.type;
521 tree.expr = translate(tree.expr, erasure(tree.expr.type));
522 if (types.elemtype(tree.expr.type) == null)
523 tree.expr.type = iterableType; // preserve type for Lower
524 tree.body = translate(tree.body);
525 result = tree;
526 }
527
528 public void visitLambda(JCLambda tree) {
529 Type prevRetType = returnType;
530 try {
531 returnType = erasure(tree.getDescriptorType(types)).getReturnType();
532 tree.params = translate(tree.params);
533 tree.body = translate(tree.body, tree.body.type == null || returnType.hasTag(VOID) ? null : returnType);
534 if (!tree.type.isIntersection()) {
535 tree.type = erasure(tree.type);
536 } else {
537 tree.type = types.erasure(types.findDescriptorSymbol(tree.type.tsym).owner.type);
538 }
539 result = tree;
540 }
541 finally {
542 returnType = prevRetType;
543 }
544 }
545
546 @Override
547 public void visitReference(JCMemberReference tree) {
548 if (needsConversionToLambda(tree)) {
549 // Convert to a lambda, and process as such
550 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree);
551 result = translate(conv.lambda());
552 } else {
553 Type t = types.skipTypeVars(tree.expr.type, false);
554 Type receiverTarget = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t);
555 if (tree.kind == ReferenceKind.UNBOUND) {
556 tree.expr = make.Type(receiverTarget);
557 } else {
558 tree.expr = translate(tree.expr, receiverTarget);
559 }
560 if (!tree.type.isIntersection()) {
561 tree.type = erasure(tree.type);
562 } else {
563 tree.type = types.erasure(types.findDescriptorSymbol(tree.type.tsym).owner.type);
564 }
565 result = tree;
566 }
567 }
568 // where
569 boolean needsVarArgsConversion(JCMemberReference tree) {
570 return tree.varargsElement != null;
571 }
572
573 /**
574 * @return Is this an array operation like clone()
575 */
576 boolean isArrayOp(JCMemberReference tree) {
577 return tree.sym.owner == syms.arrayClass;
578 }
579
580 boolean receiverAccessible(JCMemberReference tree) {
581 //hack needed to workaround 292 bug (7087658)
582 //when 292 issue is fixed we should remove this and change the backend
583 //code to always generate a method handle to an accessible method
584 return tree.ownerAccessible;
585 }
586
587 /**
588 * Erasure destroys the implementation parameter subtype
589 * relationship for intersection types.
590 * Have similar problems for union types too.
591 */
592 boolean interfaceParameterIsIntersectionOrUnionType(JCMemberReference tree) {
593 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
594 for (; tl.nonEmpty(); tl = tl.tail) {
595 Type pt = tl.head;
596 if (isIntersectionOrUnionType(pt))
597 return true;
598 }
599 return false;
600 }
601
602 boolean isIntersectionOrUnionType(Type t) {
603 return switch (t.getKind()) {
604 case INTERSECTION, UNION -> true;
605 case TYPEVAR -> {
606 TypeVar tv = (TypeVar) t;
607 yield isIntersectionOrUnionType(tv.getUpperBound());
608 }
609 default -> false;
610 };
611 }
612
613 private boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage(Symbol targetReference,
614 Symbol currentClass) {
615 return ((targetReference.flags() & PROTECTED) != 0 &&
616 targetReference.packge() != currentClass.packge());
617 }
618
619 /**
620 * This method should be called only when target release <= 14
621 * where LambdaMetaFactory does not spin nestmate classes.
622 *
623 * This method should be removed when --release 14 is not supported.
624 */
625 boolean isPrivateInOtherClass(JCMemberReference tree) {
626 return (tree.sym.flags() & PRIVATE) != 0 &&
627 !types.isSameType(
628 types.erasure(tree.sym.enclClass().asType()),
629 types.erasure(env.enclClass.sym.asType()));
630 }
631
632 /**
633 * Does this reference need to be converted to a lambda
634 * (i.e. var args need to be expanded or "super" is used)
635 */
636 boolean needsConversionToLambda(JCMemberReference tree) {
637 return interfaceParameterIsIntersectionOrUnionType(tree) ||
638 tree.hasKind(ReferenceKind.SUPER) ||
639 needsVarArgsConversion(tree) ||
640 tree.codeReflectionInfo != null ||
641 isArrayOp(tree) ||
642 (!target.runtimeUseNestAccess() && isPrivateInOtherClass(tree)) ||
643 isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, env.enclClass.sym) ||
644 !receiverAccessible(tree) ||
645 (tree.getMode() == ReferenceMode.NEW &&
646 tree.kind != ReferenceKind.ARRAY_CTOR &&
647 (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner()));
648 }
649
650 /**
651 * Converts a method reference which cannot be used directly into a lambda
652 */
653 private class MemberReferenceToLambda {
654
655 private final JCMemberReference tree;
656 private final ListBuffer<JCExpression> args = new ListBuffer<>();
657 private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
658 private final MethodSymbol owner = new MethodSymbol(0, names.empty, Type.noType, env.enclClass.sym);
659
660 private JCExpression receiverExpression = null;
661
662 MemberReferenceToLambda(JCMemberReference tree) {
663 this.tree = tree;
664 }
665
666 JCExpression lambda() {
667 int prevPos = make.pos;
668 try {
669 make.at(tree);
670
671 //body generation - this can be either a method call or a
672 //new instance creation expression, depending on the member reference kind
673 VarSymbol rcvr = addParametersReturnReceiver();
674 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
675 ? expressionInvoke(rcvr)
676 : expressionNew();
677
678 JCLambda slam = make.Lambda(params.toList(), expr);
679 slam.target = tree.target;
680 slam.owner = tree.owner;
681 slam.type = tree.type;
682 slam.pos = tree.pos;
683 slam.codeReflectionInfo = tree.codeReflectionInfo;
684 slam.wasMethodReference = true;
685 if (receiverExpression != null) {
686 // use a let expression so that the receiver expression is evaluated eagerly
687 return make.at(tree.pos).LetExpr(
688 make.VarDef(rcvr, receiverExpression), slam).setType(tree.type);
689 } else {
690 return slam;
691 }
692 } finally {
693 make.at(prevPos);
694 }
695 }
696
697 /**
698 * Generate the parameter list for the converted member reference.
699 *
700 * @return The receiver variable symbol, if any
701 */
702 VarSymbol addParametersReturnReceiver() {
703 List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
704
705 // Determine the receiver, if any
706 VarSymbol rcvr;
707 switch (tree.kind) {
708 case BOUND:
709 // The receiver is explicit in the method reference
710 rcvr = new VarSymbol(SYNTHETIC, names.fromString("rec$"), tree.getQualifierExpression().type, owner);
711 rcvr.pos = tree.pos;
712 receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
713 break;
714 case UNBOUND:
715 // The receiver is the first parameter, extract it and
716 // adjust the SAM and unerased type lists accordingly
717 rcvr = addParameter("rec$", descPTypes.head, false);
718 descPTypes = descPTypes.tail;
719 break;
720 default:
721 rcvr = null;
722 break;
723 }
724 List<Type> implPTypes = tree.sym.type.getParameterTypes();
725 int implSize = implPTypes.size();
726 int samSize = descPTypes.size();
727 // Last parameter to copy from referenced method, exclude final var args
728 int last = needsVarArgsConversion(tree) ? implSize - 1 : implSize;
729
730 for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
731 // Use the descriptor parameter type
732 Type parmType = descPTypes.head;
733 addParameter("x$" + i, parmType, true);
734
735 // Advance to the next parameter
736 implPTypes = implPTypes.tail;
737 descPTypes = descPTypes.tail;
738 }
739 // Flatten out the var args
740 for (int i = last; i < samSize; ++i) {
741 addParameter("xva$" + i, tree.varargsElement, true);
742 }
743
744 return rcvr;
745 }
746
747 /**
748 * determine the receiver of the method call - the receiver can
749 * be a type qualifier, the synthetic receiver parameter or 'super'.
750 */
751 private JCExpression expressionInvoke(VarSymbol rcvr) {
752 JCExpression qualifier =
753 (rcvr != null) ?
754 make.Ident(rcvr) :
755 tree.getQualifierExpression();
756
757 //create the qualifier expression
758 JCFieldAccess select = make.Select(qualifier, tree.sym.name);
759 select.sym = tree.sym;
760 select.type = tree.referentType;
761
762 //create the method call expression
763 JCExpression apply = make.Apply(List.nil(), select,
764 args.toList()).setType(tree.referentType.getReturnType());
765
766 TreeInfo.setVarargsElement(apply, tree.varargsElement);
767 return apply;
768 }
769
770 /**
771 * Lambda body to use for a 'new'.
772 */
773 private JCExpression expressionNew() {
774 if (tree.kind == ReferenceKind.ARRAY_CTOR) {
775 //create the array creation expression
776 JCNewArray newArr = make.NewArray(
777 make.Type(types.elemtype(tree.getQualifierExpression().type)),
778 List.of(make.Ident(params.first())),
779 null);
780 newArr.type = tree.getQualifierExpression().type;
781 return newArr;
782 } else {
783 //create the instance creation expression
784 //note that method reference syntax does not allow an explicit
785 //enclosing class (so the enclosing class is null)
786 // but this may need to be patched up later with the proxy for the outer this
787 JCNewClass newClass = make.NewClass(null,
788 List.nil(),
789 make.Type(tree.getQualifierExpression().type),
790 args.toList(),
791 null);
792 newClass.constructor = tree.sym;
793 newClass.constructorType = tree.sym.erasure(types);
794 newClass.type = tree.getQualifierExpression().type;
795 TreeInfo.setVarargsElement(newClass, tree.varargsElement);
796 return newClass;
797 }
798 }
799
800 private VarSymbol addParameter(String name, Type p, boolean genArg) {
801 VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
802 vsym.pos = tree.pos;
803 params.append(make.VarDef(vsym, null));
804 if (genArg) {
805 args.append(make.Ident(vsym));
806 }
807 return vsym;
808 }
809 }
810
811 public void visitSwitch(JCSwitch tree) {
812 tree.selector = translate(tree.selector, erasure(tree.selector.type));
813 tree.cases = translateCases(tree.cases);
814 result = tree;
815 }
816
817 public void visitCase(JCCase tree) {
818 tree.labels = translate(tree.labels, null);
819 tree.guard = translate(tree.guard, syms.booleanType);
820 tree.stats = translate(tree.stats);
821 result = tree;
822 }
823
824 @Override
825 public void visitAnyPattern(JCAnyPattern tree) {
826 result = tree;
827 }
828
829 public void visitBindingPattern(JCBindingPattern tree) {
830 tree.var = translate(tree.var, null);
831 result = tree;
832 }
833
834 @Override
835 public void visitConstantCaseLabel(JCConstantCaseLabel tree) {
836 tree.expr = translate(tree.expr, null);
837 result = tree;
838 }
839
840 @Override
841 public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
842 tree.pat = translate(tree.pat, null);
843 result = tree;
844 }
845
846 public void visitSwitchExpression(JCSwitchExpression tree) {
847 tree.selector = translate(tree.selector, erasure(tree.selector.type));
848 tree.cases = translate(tree.cases, erasure(tree.type));
849 tree.type = erasure(tree.type);
850 result = retype(tree, tree.type, pt);
851 }
852
853 public void visitRecordPattern(JCRecordPattern tree) {
854 tree.fullComponentTypes = tree.record.getRecordComponents()
855 .map(rc -> types.memberType(tree.type, rc));
856 tree.deconstructor = translate(tree.deconstructor, null);
857 tree.nested = translate(tree.nested, null);
858 result = tree;
859 }
860
861 public void visitSynchronized(JCSynchronized tree) {
862 tree.lock = translate(tree.lock, erasure(tree.lock.type));
863 tree.body = translate(tree.body);
864 result = tree;
865 }
866
867 public void visitTry(JCTry tree) {
868 tree.resources = translate(tree.resources, syms.autoCloseableType);
869 tree.body = translate(tree.body);
870 tree.catchers = translateCatchers(tree.catchers);
871 tree.finalizer = translate(tree.finalizer);
872 result = tree;
873 }
874
875 public void visitConditional(JCConditional tree) {
876 tree.cond = translate(tree.cond, syms.booleanType);
877 tree.truepart = translate(tree.truepart, erasure(tree.type));
878 tree.falsepart = translate(tree.falsepart, erasure(tree.type));
879 tree.type = erasure(tree.type);
880 result = retype(tree, tree.type, pt);
881 }
882
883 public void visitIf(JCIf tree) {
884 tree.cond = translate(tree.cond, syms.booleanType);
885 tree.thenpart = translate(tree.thenpart);
886 tree.elsepart = translate(tree.elsepart);
887 result = tree;
888 }
889
890 public void visitExec(JCExpressionStatement tree) {
891 tree.expr = translate(tree.expr, null);
892 result = tree;
893 }
894
895 public void visitReturn(JCReturn tree) {
896 if (!returnType.hasTag(VOID))
897 tree.expr = translate(tree.expr, returnType);
898 result = tree;
899 }
900
901 @Override
902 public void visitBreak(JCBreak tree) {
903 result = tree;
904 }
905
906 @Override
907 public void visitYield(JCYield tree) {
908 tree.value = translate(tree.value, erasure(tree.value.type));
909 tree.value.type = erasure(tree.value.type);
910 tree.value = retype(tree.value, tree.value.type, pt);
911 result = tree;
912 }
913
914 public void visitThrow(JCThrow tree) {
915 tree.expr = translate(tree.expr, erasure(tree.expr.type));
916 result = tree;
917 }
918
919 public void visitAssert(JCAssert tree) {
920 tree.cond = translate(tree.cond, syms.booleanType);
921 if (tree.detail != null)
922 tree.detail = translate(tree.detail, erasure(tree.detail.type));
923 result = tree;
924 }
925
926 public void visitApply(JCMethodInvocation tree) {
927 tree.meth = translate(tree.meth, null);
928 Symbol meth = TreeInfo.symbol(tree.meth);
929 Type mt = meth.erasure(types);
930 boolean useInstantiatedPtArgs = !types.isSignaturePolymorphic((MethodSymbol)meth.baseSymbol());
931 List<Type> argtypes = useInstantiatedPtArgs ?
932 tree.meth.type.getParameterTypes() :
933 mt.getParameterTypes();
934 if (meth.name == names.init && meth.owner == syms.enumSym)
935 argtypes = argtypes.tail.tail;
936 if (tree.varargsElement != null)
937 tree.varargsElement = types.erasure(tree.varargsElement);
938 else
939 if (tree.args.length() != argtypes.length()) {
940 Assert.error(String.format("Incorrect number of arguments; expected %d, found %d",
941 tree.args.length(), argtypes.length()));
942 }
943 tree.args = translateArgs(tree.args, argtypes, tree.varargsElement);
944
945 tree.type = types.erasure(tree.type);
946 // Insert casts of method invocation results as needed.
947 result = retype(tree, mt.getReturnType(), pt);
948 }
949
950 public void visitNewClass(JCNewClass tree) {
951 if (tree.encl != null) {
952 if (tree.def == null) {
953 tree.encl = translate(tree.encl, erasure(tree.encl.type));
954 } else {
955 tree.args = tree.args.prepend(attr.makeNullCheck(tree.encl));
956 tree.encl = null;
957 }
958 }
959
960 Type erasedConstructorType = tree.constructorType != null ?
961 erasure(tree.constructorType) :
962 null;
963
964 List<Type> argtypes = erasedConstructorType != null ?
965 erasedConstructorType.getParameterTypes() :
966 tree.constructor.erasure(types).getParameterTypes();
967
968 tree.clazz = translate(tree.clazz, null);
969 if (tree.varargsElement != null)
970 tree.varargsElement = types.erasure(tree.varargsElement);
971 tree.args = translateArgs(
972 tree.args, argtypes, tree.varargsElement);
973 tree.def = translate(tree.def, null);
974 if (erasedConstructorType != null)
975 tree.constructorType = erasedConstructorType;
976 tree.type = erasure(tree.type);
977 result = tree;
978 }
979
980 public void visitNewArray(JCNewArray tree) {
981 tree.elemtype = translate(tree.elemtype, null);
982 translate(tree.dims, syms.intType);
983 if (tree.type != null) {
984 tree.elems = translate(tree.elems, erasure(types.elemtype(tree.type)));
985 tree.type = erasure(tree.type);
986 } else {
987 tree.elems = translate(tree.elems, null);
988 }
989
990 result = tree;
991 }
992
993 public void visitParens(JCParens tree) {
994 tree.expr = translate(tree.expr, pt);
995 tree.type = erasure(tree.expr.type);
996 result = tree;
997 }
998
999 public void visitAssign(JCAssign tree) {
1000 tree.lhs = translate(tree.lhs, null);
1001 tree.rhs = translate(tree.rhs, erasure(tree.lhs.type));
1002 tree.type = erasure(tree.lhs.type);
1003 result = retype(tree, tree.type, pt);
1004 }
1005
1006 public void visitAssignop(JCAssignOp tree) {
1007 tree.lhs = translate(tree.lhs, null);
1008 tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
1009 tree.type = erasure(tree.type);
1010 result = tree;
1011 }
1012
1013 public void visitUnary(JCUnary tree) {
1014 tree.arg = translate(tree.arg, (tree.getTag() == Tag.NULLCHK)
1015 ? tree.type
1016 : tree.operator.type.getParameterTypes().head);
1017 result = tree;
1018 }
1019
1020 public void visitBinary(JCBinary tree) {
1021 tree.lhs = translate(tree.lhs, tree.operator.type.getParameterTypes().head);
1022 tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
1023 result = tree;
1024 }
1025
1026 public void visitAnnotatedType(JCAnnotatedType tree) {
1027 // For now, we need to keep the annotations in the tree because of the current
1028 // MultiCatch implementation wrt type annotations
1029 List<TypeCompound> mirrors = annotate.fromAnnotations(tree.annotations);
1030 tree.underlyingType = translate(tree.underlyingType);
1031 tree.type = tree.underlyingType.type.annotatedType(mirrors);
1032 result = tree;
1033 }
1034
1035 public void visitTypeCast(JCTypeCast tree) {
1036 tree.clazz = translate(tree.clazz, null);
1037 Type originalTarget = tree.type;
1038 tree.type = erasure(tree.type);
1039 JCExpression newExpression = translate(tree.expr, tree.type);
1040 if (newExpression != tree.expr) {
1041 JCTypeCast typeCast = newExpression.hasTag(Tag.TYPECAST)
1042 ? (JCTypeCast) newExpression
1043 : null;
1044 tree.expr = typeCast != null && types.isSameType(typeCast.type, tree.type)
1045 ? typeCast.expr
1046 : newExpression;
1047 }
1048 if (originalTarget.isIntersection()) {
1049 Type.IntersectionClassType ict = (Type.IntersectionClassType)originalTarget;
1050 for (Type c : ict.getExplicitComponents()) {
1051 Type ec = erasure(c);
1052 if (!types.isSameType(ec, tree.type) && (!types.isSameType(ec, pt))) {
1053 tree.expr = coerce(tree.expr, ec);
1054 }
1055 }
1056 }
1057 result = retype(tree, tree.type, pt);
1058 }
1059
1060 public void visitTypeTest(JCInstanceOf tree) {
1061 tree.pattern = translate(tree.pattern, null);
1062 if (tree.pattern.type.isPrimitive()) {
1063 tree.erasedExprOriginalType = erasure(tree.expr.type);
1064 tree.expr = translate(tree.expr, null);
1065 }
1066 else {
1067 tree.expr = translate(tree.expr, null);
1068 }
1069 result = tree;
1070 }
1071
1072 public void visitIndexed(JCArrayAccess tree) {
1073 tree.indexed = translate(tree.indexed, erasure(tree.indexed.type));
1074 tree.index = translate(tree.index, syms.intType);
1075
1076 // Insert casts of indexed expressions as needed.
1077 result = retype(tree, types.elemtype(tree.indexed.type), pt);
1078 }
1079
1080 // There ought to be nothing to rewrite here;
1081 // we don't generate code.
1082 public void visitAnnotation(JCAnnotation tree) {
1083 result = tree;
1084 }
1085
1086 public void visitIdent(JCIdent tree) {
1087 Type et = tree.sym.erasure(types);
1088
1089 // Map type variables to their bounds.
1090 if (tree.sym.kind == TYP && tree.sym.type.hasTag(TYPEVAR)) {
1091 result = make.at(tree.pos).Type(et);
1092 } else
1093 // Map constants expressions to themselves.
1094 if (tree.type.constValue() != null) {
1095 result = tree;
1096 }
1097 // Insert casts of variable uses as needed.
1098 else if (tree.sym.kind == VAR) {
1099 result = retype(tree, et, pt);
1100 }
1101 else {
1102 tree.type = erasure(tree.type);
1103 result = tree;
1104 }
1105 }
1106
1107 public void visitSelect(JCFieldAccess tree) {
1108 Type t = types.skipTypeVars(tree.selected.type, false);
1109 if (t.isCompound()) {
1110 tree.selected = coerce(
1111 translate(tree.selected, erasure(tree.selected.type)),
1112 erasure(tree.sym.owner.type));
1113 } else
1114 tree.selected = translate(tree.selected, erasure(t));
1115
1116 // Map constants expressions to themselves.
1117 if (tree.type.constValue() != null) {
1118 result = tree;
1119 }
1120 // Insert casts of variable uses as needed.
1121 else if (tree.sym.kind == VAR) {
1122 result = retype(tree, tree.sym.erasure(types), pt);
1123 }
1124 else {
1125 tree.type = erasure(tree.type);
1126 result = tree;
1127 }
1128 }
1129
1130 public void visitTypeArray(JCArrayTypeTree tree) {
1131 tree.elemtype = translate(tree.elemtype, null);
1132 tree.type = erasure(tree.type);
1133 result = tree;
1134 }
1135
1136 /** Visitor method for parameterized types.
1137 */
1138 public void visitTypeApply(JCTypeApply tree) {
1139 JCTree clazz = translate(tree.clazz, null);
1140 result = clazz;
1141 }
1142
1143 public void visitTypeIntersection(JCTypeIntersection tree) {
1144 result = translate(tree.bounds.head, null);
1145 }
1146
1147 /* ************************************************************************
1148 * utility methods
1149 *************************************************************************/
1150
1151 private Type erasure(Type t) {
1152 return types.erasure(t);
1153 }
1154
1155 /* ************************************************************************
1156 * main method
1157 *************************************************************************/
1158
1159 private Env<AttrContext> env;
1160
1161 private static final String statePreviousToFlowAssertMsg =
1162 "The current compile state [%s] of class %s is previous to WARN";
1163
1164 void translateClass(ClassSymbol c) {
1165 Type st = types.supertype(c.type);
1166 // process superclass before derived
1167 if (st.hasTag(CLASS)) {
1168 translateClass((ClassSymbol)st.tsym);
1169 }
1170
1171 Env<AttrContext> myEnv = enter.getEnv(c);
1172 if (myEnv == null || (c.flags_field & TYPE_TRANSLATED) != 0) {
1173 return;
1174 }
1175 c.flags_field |= TYPE_TRANSLATED;
1176
1177 /* The two assertions below are set for early detection of any attempt
1178 * to translate a class that:
1179 *
1180 * 1) has no compile state being it the most outer class.
1181 * We accept this condition for inner classes.
1182 *
1183 * 2) has a compile state which is previous to WARN state.
1184 */
1185 boolean envHasCompState = compileStates.get(myEnv) != null;
1186 if (!envHasCompState && c.outermostClass() == c) {
1187 Assert.error("No info for outermost class: " + myEnv.enclClass.sym);
1188 }
1189
1190 if (envHasCompState &&
1191 CompileState.WARN.isAfter(compileStates.get(myEnv))) {
1192 Assert.error(String.format(statePreviousToFlowAssertMsg,
1193 compileStates.get(myEnv), myEnv.enclClass.sym));
1194 }
1195
1196 Env<AttrContext> oldEnv = env;
1197 try {
1198 env = myEnv;
1199 // class has not been translated yet
1200
1201 TreeMaker savedMake = make;
1202 Type savedPt = pt;
1203 make = make.forToplevel(env.toplevel);
1204 pt = null;
1205 try {
1206 JCClassDecl tree = (JCClassDecl) env.tree;
1207 tree.typarams = List.nil();
1208 super.visitClassDef(tree);
1209 make.at(tree.pos);
1210 ListBuffer<JCTree> bridges = new ListBuffer<>();
1211 addBridges(tree.pos(), c, bridges);
1212 tree.defs = bridges.toList().prependList(tree.defs);
1213 tree.type = erasure(tree.type);
1214 } finally {
1215 make = savedMake;
1216 pt = savedPt;
1217 }
1218 } finally {
1219 env = oldEnv;
1220 }
1221 }
1222
1223 /** Translate a toplevel class definition.
1224 * @param cdef The definition to be translated.
1225 */
1226 public JCTree translateTopLevelClass(JCTree cdef, TreeMaker make) {
1227 // note that this method does NOT support recursion.
1228 this.make = make;
1229 pt = null;
1230 return translate(cdef, null);
1231 }
1232 }
--- EOF ---