1 /*
2 * Copyright (c) 2015, 2022, 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 import com.sun.tools.javac.code.Flags;
29 import com.sun.tools.javac.code.Symbol;
30 import com.sun.tools.javac.code.Symtab;
31 import com.sun.tools.javac.code.Type;
32 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
33 import com.sun.tools.javac.comp.Attr.ResultInfo;
34 import com.sun.tools.javac.comp.Attr.TargetInfo;
35 import com.sun.tools.javac.comp.Check.CheckContext;
36 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
37 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
38 import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
39 import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
40 import com.sun.tools.javac.comp.DeferredAttr.SwitchExpressionScanner;
41 import com.sun.tools.javac.comp.Infer.PartiallyInferredMethodType;
42 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
43 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
44 import com.sun.tools.javac.tree.JCTree;
45 import com.sun.tools.javac.tree.JCTree.JCConditional;
46 import com.sun.tools.javac.tree.JCTree.JCExpression;
47 import com.sun.tools.javac.tree.JCTree.JCLambda;
48 import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
49 import com.sun.tools.javac.tree.JCTree.JCMemberReference;
50 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
51 import com.sun.tools.javac.tree.JCTree.JCNewClass;
87 * - if A is potentially a poly expression (i.e. diamond instance creation expression), a speculative
88 * pass over A is performed; the results of such speculative attribution are then saved in a special
89 * type, so that enclosing overload resolution can be carried by simply checking compatibility against the
90 * type determined during this speculative pass.
91 *
92 * - if A is a standalone expression, regular attribution takes place.
93 *
94 * To minimize the speculative work, a cache is used, so that already computed argument types
95 * associated with a given unique source location are never recomputed multiple times.
96 */
97 public class ArgumentAttr extends JCTree.Visitor {
98
99 protected static final Context.Key<ArgumentAttr> methodAttrKey = new Context.Key<>();
100
101 private final DeferredAttr deferredAttr;
102 private final JCDiagnostic.Factory diags;
103 private final Attr attr;
104 private final Symtab syms;
105 private final Log log;
106
107 /** Attribution environment to be used. */
108 private Env<AttrContext> env;
109
110 /** Result of method attribution. */
111 Type result;
112
113 /** Cache for argument types; behavior is influenced by the currently selected cache policy. */
114 Map<UniquePos, ArgumentType<?>> argumentTypeCache = new LinkedHashMap<>();
115
116 public static ArgumentAttr instance(Context context) {
117 ArgumentAttr instance = context.get(methodAttrKey);
118 if (instance == null)
119 instance = new ArgumentAttr(context);
120 return instance;
121 }
122
123 @SuppressWarnings("this-escape")
124 protected ArgumentAttr(Context context) {
125 context.put(methodAttrKey, this);
126 deferredAttr = DeferredAttr.instance(context);
127 diags = JCDiagnostic.Factory.instance(context);
128 attr = Attr.instance(context);
129 syms = Symtab.instance(context);
130 log = Log.instance(context);
131 }
132
133 /**
134 * Set the results of method attribution.
135 */
136 void setResult(JCExpression tree, Type type) {
137 result = type;
138 if (env.info.attributionMode == DeferredAttr.AttributionMode.SPECULATIVE) {
139 //if we are in a speculative branch we can save the type in the tree itself
140 //as there's no risk of polluting the original tree.
141 tree.type = result;
142 }
143 }
144
145 /**
146 * Checks a type in the speculative tree against a given result; the type can be either a plain
147 * type or an argument type, in which case a more complex check is required.
148 */
149 Type checkSpeculative(JCTree expr, ResultInfo resultInfo) {
150 return checkSpeculative(expr, expr.type, resultInfo);
542
543 /** Compute return expressions (if needed). */
544 List<JCReturn> returnExpressions() {
545 return returnExpressions.orElseGet(() -> {
546 final List<JCReturn> res;
547 ListBuffer<JCReturn> buf = new ListBuffer<>();
548 new LambdaReturnScanner() {
549 @Override
550 public void visitReturn(JCReturn tree) {
551 buf.add(tree);
552 }
553 }.scan(speculativeTree.body);
554 res = buf.toList();
555 returnExpressions = Optional.of(res);
556 return res;
557 });
558 }
559
560 @Override
561 Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
562 try {
563 //compute target-type; this logic could be shared with Attr
564 TargetInfo targetInfo = attr.getTargetInfo(speculativeTree, resultInfo, argtypes());
565 Type lambdaType = targetInfo.descriptor;
566 Type currentTarget = targetInfo.target;
567 //check compatibility
568 checkLambdaCompatible(lambdaType, resultInfo);
569 return currentTarget;
570 } catch (FunctionDescriptorLookupError ex) {
571 resultInfo.checkContext.report(null, ex.getDiagnostic());
572 return null; //cannot get here
573 }
574 }
575
576 /** Check lambda against given target result */
577 private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) {
578 CheckContext checkContext = resultInfo.checkContext;
579 ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo);
580 switch (speculativeTree.getBodyKind()) {
581 case EXPRESSION:
582 checkSpeculative(speculativeTree.body, speculativeTree.body.type, bodyResultInfo);
583 break;
584 case STATEMENT:
585 for (JCReturn ret : returnExpressions()) {
586 checkReturnInStatementLambda(ret, bodyResultInfo);
587 }
588 break;
589 }
590
591 attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext);
592 }
|
1 /*
2 * Copyright (c) 2015, 2024, 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 import com.sun.tools.javac.code.Flags;
29 import com.sun.tools.javac.code.Symbol;
30 import com.sun.tools.javac.code.Symtab;
31 import com.sun.tools.javac.code.Type;
32 import com.sun.tools.javac.code.Types;
33 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
34 import com.sun.tools.javac.comp.Attr.ResultInfo;
35 import com.sun.tools.javac.comp.Attr.TargetInfo;
36 import com.sun.tools.javac.comp.Check.CheckContext;
37 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
38 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
39 import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
40 import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
41 import com.sun.tools.javac.comp.DeferredAttr.SwitchExpressionScanner;
42 import com.sun.tools.javac.comp.Infer.PartiallyInferredMethodType;
43 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
44 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
45 import com.sun.tools.javac.tree.JCTree;
46 import com.sun.tools.javac.tree.JCTree.JCConditional;
47 import com.sun.tools.javac.tree.JCTree.JCExpression;
48 import com.sun.tools.javac.tree.JCTree.JCLambda;
49 import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
50 import com.sun.tools.javac.tree.JCTree.JCMemberReference;
51 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
52 import com.sun.tools.javac.tree.JCTree.JCNewClass;
88 * - if A is potentially a poly expression (i.e. diamond instance creation expression), a speculative
89 * pass over A is performed; the results of such speculative attribution are then saved in a special
90 * type, so that enclosing overload resolution can be carried by simply checking compatibility against the
91 * type determined during this speculative pass.
92 *
93 * - if A is a standalone expression, regular attribution takes place.
94 *
95 * To minimize the speculative work, a cache is used, so that already computed argument types
96 * associated with a given unique source location are never recomputed multiple times.
97 */
98 public class ArgumentAttr extends JCTree.Visitor {
99
100 protected static final Context.Key<ArgumentAttr> methodAttrKey = new Context.Key<>();
101
102 private final DeferredAttr deferredAttr;
103 private final JCDiagnostic.Factory diags;
104 private final Attr attr;
105 private final Symtab syms;
106 private final Log log;
107
108 private final Types types;
109
110 /** Attribution environment to be used. */
111 private Env<AttrContext> env;
112
113 /** Result of method attribution. */
114 Type result;
115
116 /** Cache for argument types; behavior is influenced by the currently selected cache policy. */
117 Map<UniquePos, ArgumentType<?>> argumentTypeCache = new LinkedHashMap<>();
118
119 public static ArgumentAttr instance(Context context) {
120 ArgumentAttr instance = context.get(methodAttrKey);
121 if (instance == null)
122 instance = new ArgumentAttr(context);
123 return instance;
124 }
125
126 @SuppressWarnings("this-escape")
127 protected ArgumentAttr(Context context) {
128 context.put(methodAttrKey, this);
129 deferredAttr = DeferredAttr.instance(context);
130 diags = JCDiagnostic.Factory.instance(context);
131 attr = Attr.instance(context);
132 syms = Symtab.instance(context);
133 log = Log.instance(context);
134 types = Types.instance(context);
135 }
136
137 /**
138 * Set the results of method attribution.
139 */
140 void setResult(JCExpression tree, Type type) {
141 result = type;
142 if (env.info.attributionMode == DeferredAttr.AttributionMode.SPECULATIVE) {
143 //if we are in a speculative branch we can save the type in the tree itself
144 //as there's no risk of polluting the original tree.
145 tree.type = result;
146 }
147 }
148
149 /**
150 * Checks a type in the speculative tree against a given result; the type can be either a plain
151 * type or an argument type, in which case a more complex check is required.
152 */
153 Type checkSpeculative(JCTree expr, ResultInfo resultInfo) {
154 return checkSpeculative(expr, expr.type, resultInfo);
546
547 /** Compute return expressions (if needed). */
548 List<JCReturn> returnExpressions() {
549 return returnExpressions.orElseGet(() -> {
550 final List<JCReturn> res;
551 ListBuffer<JCReturn> buf = new ListBuffer<>();
552 new LambdaReturnScanner() {
553 @Override
554 public void visitReturn(JCReturn tree) {
555 buf.add(tree);
556 }
557 }.scan(speculativeTree.body);
558 res = buf.toList();
559 returnExpressions = Optional.of(res);
560 return res;
561 });
562 }
563
564 @Override
565 Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
566 if (types.isQuoted(resultInfo.pt)) {
567 // quoted lambda - always correct
568 return resultInfo.pt;
569 } else {
570 try {
571 //compute target-type; this logic could be shared with Attr
572 TargetInfo targetInfo = attr.getTargetInfo(speculativeTree, resultInfo, argtypes());
573 Type lambdaType = targetInfo.descriptor;
574 Type currentTarget = targetInfo.target;
575 //check compatibility
576 checkLambdaCompatible(lambdaType, resultInfo);
577 return currentTarget;
578 } catch (FunctionDescriptorLookupError ex) {
579 resultInfo.checkContext.report(null, ex.getDiagnostic());
580 return null; //cannot get here
581 }
582 }
583 }
584
585 /** Check lambda against given target result */
586 private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) {
587 CheckContext checkContext = resultInfo.checkContext;
588 ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo);
589 switch (speculativeTree.getBodyKind()) {
590 case EXPRESSION:
591 checkSpeculative(speculativeTree.body, speculativeTree.body.type, bodyResultInfo);
592 break;
593 case STATEMENT:
594 for (JCReturn ret : returnExpressions()) {
595 checkReturnInStatementLambda(ret, bodyResultInfo);
596 }
597 break;
598 }
599
600 attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext);
601 }
|