langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java
changeset 15039 80190ab051c0
parent 14547 86d8d242b0c4
child 15374 fb8f6acf09cc
equal deleted inserted replaced
15038:3ad27d268874 15039:80190ab051c0
    36 import com.sun.tools.javac.tree.JCTree.*;
    36 import com.sun.tools.javac.tree.JCTree.*;
    37 
    37 
    38 import javax.tools.JavaFileObject;
    38 import javax.tools.JavaFileObject;
    39 
    39 
    40 import java.util.ArrayList;
    40 import java.util.ArrayList;
       
    41 import java.util.EnumSet;
    41 import java.util.LinkedHashSet;
    42 import java.util.LinkedHashSet;
    42 import java.util.Map;
    43 import java.util.Map;
    43 import java.util.Queue;
    44 import java.util.Queue;
    44 import java.util.Set;
    45 import java.util.Set;
    45 import java.util.WeakHashMap;
    46 import java.util.WeakHashMap;
   175          * round is performed on the underlying AST node. There can be only one
   176          * round is performed on the underlying AST node. There can be only one
   176          * speculative round for a given target method symbol; moreover, a normal
   177          * speculative round for a given target method symbol; moreover, a normal
   177          * attribution round must follow one or more speculative rounds.
   178          * attribution round must follow one or more speculative rounds.
   178          */
   179          */
   179         Type check(ResultInfo resultInfo) {
   180         Type check(ResultInfo resultInfo) {
       
   181             return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter);
       
   182         }
       
   183 
       
   184         Type check(ResultInfo resultInfo, List<Type> stuckVars, DeferredTypeCompleter deferredTypeCompleter) {
   180             DeferredAttrContext deferredAttrContext =
   185             DeferredAttrContext deferredAttrContext =
   181                     resultInfo.checkContext.deferredAttrContext();
   186                     resultInfo.checkContext.deferredAttrContext();
   182             Assert.check(deferredAttrContext != emptyDeferredAttrContext);
   187             Assert.check(deferredAttrContext != emptyDeferredAttrContext);
   183             List<Type> stuckVars = stuckVars(tree, env, resultInfo);
       
   184             if (stuckVars.nonEmpty()) {
   188             if (stuckVars.nonEmpty()) {
   185                 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
   189                 deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
   186                 return Type.noType;
   190                 return Type.noType;
   187             } else {
   191             } else {
   188                 try {
   192                 try {
   189                     switch (deferredAttrContext.mode) {
   193                     return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
   190                         case SPECULATIVE:
       
   191                             Assert.check(mode == null ||
       
   192                                     (mode == AttrMode.SPECULATIVE &&
       
   193                                     speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE)));
       
   194                             JCTree speculativeTree = attribSpeculative(tree, env, resultInfo);
       
   195                             speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
       
   196                             return speculativeTree.type;
       
   197                         case CHECK:
       
   198                             Assert.check(mode == AttrMode.SPECULATIVE);
       
   199                             return attr.attribTree(tree, env, resultInfo);
       
   200                     }
       
   201                     Assert.error();
       
   202                     return null;
       
   203                 } finally {
   194                 } finally {
   204                     mode = deferredAttrContext.mode;
   195                     mode = deferredAttrContext.mode;
   205                 }
   196                 }
   206             }
   197             }
   207         }
   198         }
   208     }
   199     }
       
   200 
       
   201     /**
       
   202      * A completer for deferred types. Defines an entry point for type-checking
       
   203      * a deferred type.
       
   204      */
       
   205     interface DeferredTypeCompleter {
       
   206         /**
       
   207          * Entry point for type-checking a deferred type. Depending on the
       
   208          * circumstances, type-checking could amount to full attribution
       
   209          * or partial structural check (aka potential applicability).
       
   210          */
       
   211         Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
       
   212     }
       
   213 
       
   214     /**
       
   215      * A basic completer for deferred types. This completer type-checks a deferred type
       
   216      * using attribution; depending on the attribution mode, this could be either standard
       
   217      * or speculative attribution.
       
   218      */
       
   219     DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
       
   220         public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
       
   221             switch (deferredAttrContext.mode) {
       
   222                 case SPECULATIVE:
       
   223                     Assert.check(dt.mode == null ||
       
   224                             (dt.mode == AttrMode.SPECULATIVE &&
       
   225                             dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE)));
       
   226                     JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
       
   227                     dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
       
   228                     return speculativeTree.type;
       
   229                 case CHECK:
       
   230                     Assert.check(dt.mode == AttrMode.SPECULATIVE);
       
   231                     return attr.attribTree(dt.tree, dt.env, resultInfo);
       
   232             }
       
   233             Assert.error();
       
   234             return null;
       
   235         }
       
   236     };
   209 
   237 
   210     /**
   238     /**
   211      * The 'mode' in which the deferred type is to be type-checked
   239      * The 'mode' in which the deferred type is to be type-checked
   212      */
   240      */
   213     public enum AttrMode {
   241     public enum AttrMode {
   496     @SuppressWarnings("fallthrough")
   524     @SuppressWarnings("fallthrough")
   497     List<Type> stuckVars(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
   525     List<Type> stuckVars(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
   498                 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
   526                 if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
   499             return List.nil();
   527             return List.nil();
   500         } else {
   528         } else {
   501             StuckChecker sc = new StuckChecker(resultInfo, env);
   529             return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext());
       
   530         }
       
   531     }
       
   532     //where
       
   533         private List<Type> stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) {
       
   534             StuckChecker sc = new StuckChecker(pt, inferenceContext);
   502             sc.scan(tree);
   535             sc.scan(tree);
   503             return List.from(sc.stuckVars);
   536             return List.from(sc.stuckVars);
       
   537         }
       
   538 
       
   539     /**
       
   540      * A special tree scanner that would only visit portions of a given tree.
       
   541      * The set of nodes visited by the scanner can be customized at construction-time.
       
   542      */
       
   543     abstract static class FilterScanner extends TreeScanner {
       
   544 
       
   545         final Filter<JCTree> treeFilter;
       
   546 
       
   547         FilterScanner(final Set<JCTree.Tag> validTags) {
       
   548             this.treeFilter = new Filter<JCTree>() {
       
   549                 public boolean accepts(JCTree t) {
       
   550                     return validTags.contains(t.getTag());
       
   551                 }
       
   552             };
       
   553         }
       
   554 
       
   555         @Override
       
   556         public void scan(JCTree tree) {
       
   557             if (tree != null) {
       
   558                 if (treeFilter.accepts(tree)) {
       
   559                     super.scan(tree);
       
   560                 } else {
       
   561                     skip(tree);
       
   562                 }
       
   563             }
       
   564         }
       
   565 
       
   566         /**
       
   567          * handler that is executed when a node has been discarded
       
   568          */
       
   569         abstract void skip(JCTree tree);
       
   570     }
       
   571 
       
   572     /**
       
   573      * A tree scanner suitable for visiting the target-type dependent nodes of
       
   574      * a given argument expression.
       
   575      */
       
   576     static class PolyScanner extends FilterScanner {
       
   577 
       
   578         PolyScanner() {
       
   579             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
       
   580         }
       
   581 
       
   582         @Override
       
   583         void skip(JCTree tree) {
       
   584             //do nothing
       
   585         }
       
   586     }
       
   587 
       
   588     /**
       
   589      * A tree scanner suitable for visiting the target-type dependent nodes nested
       
   590      * within a lambda expression body.
       
   591      */
       
   592     static class LambdaReturnScanner extends FilterScanner {
       
   593 
       
   594         LambdaReturnScanner() {
       
   595             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
       
   596                     FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
       
   597         }
       
   598 
       
   599         @Override
       
   600         void skip(JCTree tree) {
       
   601             //do nothing
   504         }
   602         }
   505     }
   603     }
   506 
   604 
   507     /**
   605     /**
   508      * This visitor is used to check that structural expressions conform
   606      * This visitor is used to check that structural expressions conform
   509      * to their target - this step is required as inference could end up
   607      * to their target - this step is required as inference could end up
   510      * inferring types that make some of the nested expressions incompatible
   608      * inferring types that make some of the nested expressions incompatible
   511      * with their corresponding instantiated target
   609      * with their corresponding instantiated target
   512      */
   610      */
   513     class StuckChecker extends TreeScanner {
   611     class StuckChecker extends PolyScanner {
   514 
   612 
   515         Type pt;
   613         Type pt;
   516         Filter<JCTree> treeFilter;
       
   517         Infer.InferenceContext inferenceContext;
   614         Infer.InferenceContext inferenceContext;
   518         Set<Type> stuckVars = new LinkedHashSet<Type>();
   615         Set<Type> stuckVars = new LinkedHashSet<Type>();
   519         Env<AttrContext> env;
   616 
   520 
   617         StuckChecker(Type pt, Infer.InferenceContext inferenceContext) {
   521         final Filter<JCTree> argsFilter = new Filter<JCTree>() {
   618             this.pt = pt;
   522             public boolean accepts(JCTree t) {
   619             this.inferenceContext = inferenceContext;
   523                 switch (t.getTag()) {
       
   524                     case CONDEXPR:
       
   525                     case LAMBDA:
       
   526                     case PARENS:
       
   527                     case REFERENCE:
       
   528                         return true;
       
   529                     default:
       
   530                         return false;
       
   531                 }
       
   532             }
       
   533         };
       
   534 
       
   535         final Filter<JCTree> lambdaBodyFilter = new Filter<JCTree>() {
       
   536             public boolean accepts(JCTree t) {
       
   537                 switch (t.getTag()) {
       
   538                     case BLOCK: case CASE: case CATCH: case DOLOOP:
       
   539                     case FOREACHLOOP: case FORLOOP: case RETURN:
       
   540                     case SYNCHRONIZED: case SWITCH: case TRY: case WHILELOOP:
       
   541                         return true;
       
   542                     default:
       
   543                         return false;
       
   544                 }
       
   545             }
       
   546         };
       
   547 
       
   548         StuckChecker(ResultInfo resultInfo, Env<AttrContext> env) {
       
   549             this.pt = resultInfo.pt;
       
   550             this.inferenceContext = resultInfo.checkContext.inferenceContext();
       
   551             this.treeFilter = argsFilter;
       
   552             this.env = env;
       
   553         }
       
   554 
       
   555         @Override
       
   556         public void scan(JCTree tree) {
       
   557             if (tree != null && treeFilter.accepts(tree)) {
       
   558                 super.scan(tree);
       
   559             }
       
   560         }
   620         }
   561 
   621 
   562         @Override
   622         @Override
   563         public void visitLambda(JCLambda tree) {
   623         public void visitLambda(JCLambda tree) {
   564             Type prevPt = pt;
   624             if (inferenceContext.inferenceVars().contains(pt)) {
   565             Filter<JCTree> prevFilter = treeFilter;
   625                 stuckVars.add(pt);
   566             try {
   626             }
   567                 if (inferenceContext.inferenceVars().contains(pt)) {
   627             if (!types.isFunctionalInterface(pt.tsym)) {
   568                     stuckVars.add(pt);
   628                 return;
   569                 }
   629             }
   570                 if (!types.isFunctionalInterface(pt.tsym)) {
   630             Type descType = types.findDescriptorType(pt);
   571                     return;
   631             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   572                 }
   632             if (!TreeInfo.isExplicitLambda(tree) &&
   573                 Type descType = types.findDescriptorType(pt);
   633                     freeArgVars.nonEmpty()) {
   574                 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   634                 stuckVars.addAll(freeArgVars);
   575                 if (!TreeInfo.isExplicitLambda(tree) &&
   635             }
   576                         freeArgVars.nonEmpty()) {
   636             scanLambdaBody(tree, descType.getReturnType());
   577                     stuckVars.addAll(freeArgVars);
       
   578                 }
       
   579                 pt = descType.getReturnType();
       
   580                 if (tree.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
       
   581                     scan(tree.getBody());
       
   582                 } else {
       
   583                     treeFilter = lambdaBodyFilter;
       
   584                     super.visitLambda(tree);
       
   585                 }
       
   586             } finally {
       
   587                 pt = prevPt;
       
   588                 treeFilter = prevFilter;
       
   589             }
       
   590         }
   637         }
   591 
   638 
   592         @Override
   639         @Override
   593         public void visitReference(JCMemberReference tree) {
   640         public void visitReference(JCMemberReference tree) {
   594             scan(tree.expr);
   641             scan(tree.expr);
   603             Type descType = types.findDescriptorType(pt);
   650             Type descType = types.findDescriptorType(pt);
   604             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   651             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   605             stuckVars.addAll(freeArgVars);
   652             stuckVars.addAll(freeArgVars);
   606         }
   653         }
   607 
   654 
   608         @Override
   655         void scanLambdaBody(JCLambda lambda, final Type pt) {
   609         public void visitReturn(JCReturn tree) {
   656             if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
   610             Filter<JCTree> prevFilter = treeFilter;
   657                 stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext));
   611             try {
   658             } else {
   612                 treeFilter = argsFilter;
   659                 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
   613                 if (tree.expr != null) {
   660                     @Override
   614                     scan(tree.expr);
   661                     public void visitReturn(JCReturn tree) {
   615                 }
   662                         if (tree.expr != null) {
   616             } finally {
   663                             stuckVars.addAll(stuckVarsInternal(tree.expr, pt, inferenceContext));
   617                 treeFilter = prevFilter;
   664                         }
       
   665                     }
       
   666                 };
       
   667                 lambdaScanner.scan(lambda.body);
   618             }
   668             }
   619         }
   669         }
   620     }
   670     }
   621 }
   671 }