< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java

Print this page

   1 /*
   2  * Copyright (c) 2012, 2021, 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

 817          * Structural checker for stuck expressions
 818          */
 819         class StructuralStuckChecker extends TreeScanner {
 820 
 821             ResultInfo resultInfo;
 822             InferenceContext inferenceContext;
 823             Env<AttrContext> env;
 824 
 825             public void check(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 826                 this.resultInfo = resultInfo;
 827                 this.inferenceContext = deferredAttrContext.inferenceContext;
 828                 this.env = dt.env;
 829                 dt.tree.accept(this);
 830                 dt.speculativeCache.put(stuckTree, resultInfo);
 831             }
 832 
 833             @Override
 834             public void visitLambda(JCLambda tree) {
 835                 Check.CheckContext checkContext = resultInfo.checkContext;
 836                 Type pt = resultInfo.pt;
 837                 if (!inferenceContext.inferencevars.contains(pt)) {
 838                     //must be a functional descriptor
 839                     Type descriptorType = null;
 840                     try {
 841                         descriptorType = types.findDescriptorType(pt);
 842                     } catch (Types.FunctionDescriptorLookupError ex) {
 843                         checkContext.report(null, ex.getDiagnostic());
 844                     }
 845 
 846                     if (descriptorType.getParameterTypes().length() != tree.params.length()) {
 847                         checkContext.report(tree,
 848                                 diags.fragment(Fragments.IncompatibleArgTypesInLambda));
 849                     }
 850 
 851                     Type currentReturnType = descriptorType.getReturnType();
 852                     boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
 853                     if (tree.getBodyKind() == BodyKind.EXPRESSION) {
 854                         boolean isExpressionCompatible = !returnTypeIsVoid ||
 855                             TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
 856                         if (!isExpressionCompatible) {
 857                             resultInfo.checkContext.report(tree.pos(),

1101                 }
1102             });
1103             return super.visit(dt);
1104         }
1105 
1106         private List<Type> map(List<Type> ts, List<Type> pts) {
1107             if (ts.nonEmpty()) {
1108                 List<Type> tail1 = map(ts.tail, pts != null ? pts.tail : null);
1109                 Type t = visit(ts.head, pts != null && pts.nonEmpty() ? pts.head : null);
1110                 if (tail1 != ts.tail || t != ts.head)
1111                     return tail1.prepend(t);
1112             }
1113             return ts;
1114         }
1115     }
1116 
1117     /**
1118      * A special tree scanner that would only visit portions of a given tree.
1119      * The set of nodes visited by the scanner can be customized at construction-time.
1120      */
1121     abstract static class FilterScanner extends com.sun.tools.javac.tree.TreeScanner {
1122 
1123         final Predicate<JCTree> treeFilter;
1124 
1125         FilterScanner(final Set<JCTree.Tag> validTags) {
1126             this.treeFilter = t -> validTags.contains(t.getTag());
1127         }
1128 
1129         @Override
1130         public void scan(JCTree tree) {
1131             if (tree != null) {
1132                 if (treeFilter.test(tree)) {
1133                     super.scan(tree);
1134                 } else {
1135                     skip(tree);
1136                 }
1137             }
1138         }
1139 
1140         /**
1141          * handler that is executed when a node has been discarded
1142          */
1143         void skip(JCTree tree) {}
1144     }
1145 
1146     /**
1147      * A tree scanner suitable for visiting the target-type dependent nodes of
1148      * a given argument expression.
1149      */
1150     static class PolyScanner extends FilterScanner {
1151 
1152         PolyScanner() {
1153             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE, SWITCH_EXPRESSION));
1154         }
1155     }
1156 
1157     /**
1158      * A tree scanner suitable for visiting the target-type dependent nodes nested
1159      * within a lambda expression body.
1160      */
1161     static class LambdaReturnScanner extends FilterScanner {
1162 
1163         LambdaReturnScanner() {

1209         public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1210             this.pt = resultInfo.pt;
1211             this.inferenceContext = resultInfo.checkContext.inferenceContext();
1212             scan(dt.tree);
1213             if (!stuckVars.isEmpty()) {
1214                 resultInfo.checkContext.inferenceContext()
1215                         .addFreeTypeListener(List.from(stuckVars), this);
1216             }
1217         }
1218 
1219         @Override
1220         public void typesInferred(InferenceContext inferenceContext) {
1221             stuckVars.clear();
1222         }
1223 
1224         @Override
1225         public void visitLambda(JCLambda tree) {
1226             if (inferenceContext.inferenceVars().contains(pt)) {
1227                 stuckVars.add(pt);
1228             }
1229             if (!types.isFunctionalInterface(pt)) {
1230                 return;
1231             }
1232             Type descType = types.findDescriptorType(pt);
1233             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1234             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
1235                     freeArgVars.nonEmpty()) {
1236                 stuckVars.addAll(freeArgVars);
1237                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1238                 depVars.addAll(inferenceContext.freeVarsIn(descType.getThrownTypes()));
1239             }
1240             scanLambdaBody(tree, descType.getReturnType());
1241         }
1242 
1243         @Override
1244         public void visitReference(JCMemberReference tree) {
1245             scan(tree.expr);
1246             if (inferenceContext.inferenceVars().contains(pt)) {
1247                 stuckVars.add(pt);
1248                 return;
1249             }

   1 /*
   2  * Copyright (c) 2012, 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

 817          * Structural checker for stuck expressions
 818          */
 819         class StructuralStuckChecker extends TreeScanner {
 820 
 821             ResultInfo resultInfo;
 822             InferenceContext inferenceContext;
 823             Env<AttrContext> env;
 824 
 825             public void check(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 826                 this.resultInfo = resultInfo;
 827                 this.inferenceContext = deferredAttrContext.inferenceContext;
 828                 this.env = dt.env;
 829                 dt.tree.accept(this);
 830                 dt.speculativeCache.put(stuckTree, resultInfo);
 831             }
 832 
 833             @Override
 834             public void visitLambda(JCLambda tree) {
 835                 Check.CheckContext checkContext = resultInfo.checkContext;
 836                 Type pt = resultInfo.pt;
 837                 if (!types.isQuoted(pt) && !inferenceContext.inferencevars.contains(pt)) {
 838                     //must be a functional descriptor
 839                     Type descriptorType = null;
 840                     try {
 841                         descriptorType = types.findDescriptorType(pt);
 842                     } catch (Types.FunctionDescriptorLookupError ex) {
 843                         checkContext.report(null, ex.getDiagnostic());
 844                     }
 845 
 846                     if (descriptorType.getParameterTypes().length() != tree.params.length()) {
 847                         checkContext.report(tree,
 848                                 diags.fragment(Fragments.IncompatibleArgTypesInLambda));
 849                     }
 850 
 851                     Type currentReturnType = descriptorType.getReturnType();
 852                     boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
 853                     if (tree.getBodyKind() == BodyKind.EXPRESSION) {
 854                         boolean isExpressionCompatible = !returnTypeIsVoid ||
 855                             TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
 856                         if (!isExpressionCompatible) {
 857                             resultInfo.checkContext.report(tree.pos(),

1101                 }
1102             });
1103             return super.visit(dt);
1104         }
1105 
1106         private List<Type> map(List<Type> ts, List<Type> pts) {
1107             if (ts.nonEmpty()) {
1108                 List<Type> tail1 = map(ts.tail, pts != null ? pts.tail : null);
1109                 Type t = visit(ts.head, pts != null && pts.nonEmpty() ? pts.head : null);
1110                 if (tail1 != ts.tail || t != ts.head)
1111                     return tail1.prepend(t);
1112             }
1113             return ts;
1114         }
1115     }
1116 
1117     /**
1118      * A special tree scanner that would only visit portions of a given tree.
1119      * The set of nodes visited by the scanner can be customized at construction-time.
1120      */
1121     public abstract static class FilterScanner extends com.sun.tools.javac.tree.TreeScanner {
1122 
1123         final Predicate<JCTree> treeFilter;
1124 
1125         protected FilterScanner(final Set<JCTree.Tag> validTags) {
1126             this.treeFilter = t -> validTags.contains(t.getTag());
1127         }
1128 
1129         @Override
1130         public void scan(JCTree tree) {
1131             if (tree != null) {
1132                 if (treeFilter.test(tree)) {
1133                     super.scan(tree);
1134                 } else {
1135                     skip(tree);
1136                 }
1137             }
1138         }
1139 
1140         /**
1141          * handler that is executed when a node has been discarded
1142          */
1143         protected void skip(JCTree tree) {}
1144     }
1145 
1146     /**
1147      * A tree scanner suitable for visiting the target-type dependent nodes of
1148      * a given argument expression.
1149      */
1150     static class PolyScanner extends FilterScanner {
1151 
1152         PolyScanner() {
1153             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE, SWITCH_EXPRESSION));
1154         }
1155     }
1156 
1157     /**
1158      * A tree scanner suitable for visiting the target-type dependent nodes nested
1159      * within a lambda expression body.
1160      */
1161     static class LambdaReturnScanner extends FilterScanner {
1162 
1163         LambdaReturnScanner() {

1209         public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1210             this.pt = resultInfo.pt;
1211             this.inferenceContext = resultInfo.checkContext.inferenceContext();
1212             scan(dt.tree);
1213             if (!stuckVars.isEmpty()) {
1214                 resultInfo.checkContext.inferenceContext()
1215                         .addFreeTypeListener(List.from(stuckVars), this);
1216             }
1217         }
1218 
1219         @Override
1220         public void typesInferred(InferenceContext inferenceContext) {
1221             stuckVars.clear();
1222         }
1223 
1224         @Override
1225         public void visitLambda(JCLambda tree) {
1226             if (inferenceContext.inferenceVars().contains(pt)) {
1227                 stuckVars.add(pt);
1228             }
1229             if (types.isQuoted(pt) || !types.isFunctionalInterface(pt)) {
1230                 return;
1231             }
1232             Type descType = types.findDescriptorType(pt);
1233             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1234             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
1235                     freeArgVars.nonEmpty()) {
1236                 stuckVars.addAll(freeArgVars);
1237                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1238                 depVars.addAll(inferenceContext.freeVarsIn(descType.getThrownTypes()));
1239             }
1240             scanLambdaBody(tree, descType.getReturnType());
1241         }
1242 
1243         @Override
1244         public void visitReference(JCMemberReference tree) {
1245             scan(tree.expr);
1246             if (inferenceContext.inferenceVars().contains(pt)) {
1247                 stuckVars.add(pt);
1248                 return;
1249             }
< prev index next >