8005184: Restructure DeferredAttr to allow pluggable deferred type completers

Tue, 08 Jan 2013 10:17:29 +0100

author
mcimadamore
date
Tue, 08 Jan 2013 10:17:29 +0100
changeset 1481
d07340b61e6a
parent 1480
db91d860156a
child 1482
954541f13717

8005184: Restructure DeferredAttr to allow pluggable deferred type completers
Summary: Add hooks to generalize deferred type completion via custom helper objects
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Jan 08 10:16:26 2013 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Jan 08 10:17:29 2013 +0100
     1.3 @@ -38,6 +38,7 @@
     1.4  import javax.tools.JavaFileObject;
     1.5  
     1.6  import java.util.ArrayList;
     1.7 +import java.util.EnumSet;
     1.8  import java.util.LinkedHashSet;
     1.9  import java.util.Map;
    1.10  import java.util.Queue;
    1.11 @@ -177,29 +178,19 @@
    1.12           * attribution round must follow one or more speculative rounds.
    1.13           */
    1.14          Type check(ResultInfo resultInfo) {
    1.15 +            return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter);
    1.16 +        }
    1.17 +
    1.18 +        Type check(ResultInfo resultInfo, List<Type> stuckVars, DeferredTypeCompleter deferredTypeCompleter) {
    1.19              DeferredAttrContext deferredAttrContext =
    1.20                      resultInfo.checkContext.deferredAttrContext();
    1.21              Assert.check(deferredAttrContext != emptyDeferredAttrContext);
    1.22 -            List<Type> stuckVars = stuckVars(tree, env, resultInfo);
    1.23              if (stuckVars.nonEmpty()) {
    1.24                  deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars);
    1.25                  return Type.noType;
    1.26              } else {
    1.27                  try {
    1.28 -                    switch (deferredAttrContext.mode) {
    1.29 -                        case SPECULATIVE:
    1.30 -                            Assert.check(mode == null ||
    1.31 -                                    (mode == AttrMode.SPECULATIVE &&
    1.32 -                                    speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE)));
    1.33 -                            JCTree speculativeTree = attribSpeculative(tree, env, resultInfo);
    1.34 -                            speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
    1.35 -                            return speculativeTree.type;
    1.36 -                        case CHECK:
    1.37 -                            Assert.check(mode == AttrMode.SPECULATIVE);
    1.38 -                            return attr.attribTree(tree, env, resultInfo);
    1.39 -                    }
    1.40 -                    Assert.error();
    1.41 -                    return null;
    1.42 +                    return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
    1.43                  } finally {
    1.44                      mode = deferredAttrContext.mode;
    1.45                  }
    1.46 @@ -208,6 +199,43 @@
    1.47      }
    1.48  
    1.49      /**
    1.50 +     * A completer for deferred types. Defines an entry point for type-checking
    1.51 +     * a deferred type.
    1.52 +     */
    1.53 +    interface DeferredTypeCompleter {
    1.54 +        /**
    1.55 +         * Entry point for type-checking a deferred type. Depending on the
    1.56 +         * circumstances, type-checking could amount to full attribution
    1.57 +         * or partial structural check (aka potential applicability).
    1.58 +         */
    1.59 +        Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
    1.60 +    }
    1.61 +
    1.62 +    /**
    1.63 +     * A basic completer for deferred types. This completer type-checks a deferred type
    1.64 +     * using attribution; depending on the attribution mode, this could be either standard
    1.65 +     * or speculative attribution.
    1.66 +     */
    1.67 +    DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
    1.68 +        public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
    1.69 +            switch (deferredAttrContext.mode) {
    1.70 +                case SPECULATIVE:
    1.71 +                    Assert.check(dt.mode == null ||
    1.72 +                            (dt.mode == AttrMode.SPECULATIVE &&
    1.73 +                            dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE)));
    1.74 +                    JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
    1.75 +                    dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase);
    1.76 +                    return speculativeTree.type;
    1.77 +                case CHECK:
    1.78 +                    Assert.check(dt.mode == AttrMode.SPECULATIVE);
    1.79 +                    return attr.attribTree(dt.tree, dt.env, resultInfo);
    1.80 +            }
    1.81 +            Assert.error();
    1.82 +            return null;
    1.83 +        }
    1.84 +    };
    1.85 +
    1.86 +    /**
    1.87       * The 'mode' in which the deferred type is to be type-checked
    1.88       */
    1.89      public enum AttrMode {
    1.90 @@ -498,10 +526,80 @@
    1.91                  if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
    1.92              return List.nil();
    1.93          } else {
    1.94 -            StuckChecker sc = new StuckChecker(resultInfo, env);
    1.95 +            return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext());
    1.96 +        }
    1.97 +    }
    1.98 +    //where
    1.99 +        private List<Type> stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) {
   1.100 +            StuckChecker sc = new StuckChecker(pt, inferenceContext);
   1.101              sc.scan(tree);
   1.102              return List.from(sc.stuckVars);
   1.103          }
   1.104 +
   1.105 +    /**
   1.106 +     * A special tree scanner that would only visit portions of a given tree.
   1.107 +     * The set of nodes visited by the scanner can be customized at construction-time.
   1.108 +     */
   1.109 +    abstract static class FilterScanner extends TreeScanner {
   1.110 +
   1.111 +        final Filter<JCTree> treeFilter;
   1.112 +
   1.113 +        FilterScanner(final Set<JCTree.Tag> validTags) {
   1.114 +            this.treeFilter = new Filter<JCTree>() {
   1.115 +                public boolean accepts(JCTree t) {
   1.116 +                    return validTags.contains(t.getTag());
   1.117 +                }
   1.118 +            };
   1.119 +        }
   1.120 +
   1.121 +        @Override
   1.122 +        public void scan(JCTree tree) {
   1.123 +            if (tree != null) {
   1.124 +                if (treeFilter.accepts(tree)) {
   1.125 +                    super.scan(tree);
   1.126 +                } else {
   1.127 +                    skip(tree);
   1.128 +                }
   1.129 +            }
   1.130 +        }
   1.131 +
   1.132 +        /**
   1.133 +         * handler that is executed when a node has been discarded
   1.134 +         */
   1.135 +        abstract void skip(JCTree tree);
   1.136 +    }
   1.137 +
   1.138 +    /**
   1.139 +     * A tree scanner suitable for visiting the target-type dependent nodes of
   1.140 +     * a given argument expression.
   1.141 +     */
   1.142 +    static class PolyScanner extends FilterScanner {
   1.143 +
   1.144 +        PolyScanner() {
   1.145 +            super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
   1.146 +        }
   1.147 +
   1.148 +        @Override
   1.149 +        void skip(JCTree tree) {
   1.150 +            //do nothing
   1.151 +        }
   1.152 +    }
   1.153 +
   1.154 +    /**
   1.155 +     * A tree scanner suitable for visiting the target-type dependent nodes nested
   1.156 +     * within a lambda expression body.
   1.157 +     */
   1.158 +    static class LambdaReturnScanner extends FilterScanner {
   1.159 +
   1.160 +        LambdaReturnScanner() {
   1.161 +            super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
   1.162 +                    FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
   1.163 +        }
   1.164 +
   1.165 +        @Override
   1.166 +        void skip(JCTree tree) {
   1.167 +            //do nothing
   1.168 +        }
   1.169      }
   1.170  
   1.171      /**
   1.172 @@ -510,83 +608,32 @@
   1.173       * inferring types that make some of the nested expressions incompatible
   1.174       * with their corresponding instantiated target
   1.175       */
   1.176 -    class StuckChecker extends TreeScanner {
   1.177 +    class StuckChecker extends PolyScanner {
   1.178  
   1.179          Type pt;
   1.180 -        Filter<JCTree> treeFilter;
   1.181          Infer.InferenceContext inferenceContext;
   1.182          Set<Type> stuckVars = new LinkedHashSet<Type>();
   1.183 -        Env<AttrContext> env;
   1.184  
   1.185 -        final Filter<JCTree> argsFilter = new Filter<JCTree>() {
   1.186 -            public boolean accepts(JCTree t) {
   1.187 -                switch (t.getTag()) {
   1.188 -                    case CONDEXPR:
   1.189 -                    case LAMBDA:
   1.190 -                    case PARENS:
   1.191 -                    case REFERENCE:
   1.192 -                        return true;
   1.193 -                    default:
   1.194 -                        return false;
   1.195 -                }
   1.196 -            }
   1.197 -        };
   1.198 -
   1.199 -        final Filter<JCTree> lambdaBodyFilter = new Filter<JCTree>() {
   1.200 -            public boolean accepts(JCTree t) {
   1.201 -                switch (t.getTag()) {
   1.202 -                    case BLOCK: case CASE: case CATCH: case DOLOOP:
   1.203 -                    case FOREACHLOOP: case FORLOOP: case RETURN:
   1.204 -                    case SYNCHRONIZED: case SWITCH: case TRY: case WHILELOOP:
   1.205 -                        return true;
   1.206 -                    default:
   1.207 -                        return false;
   1.208 -                }
   1.209 -            }
   1.210 -        };
   1.211 -
   1.212 -        StuckChecker(ResultInfo resultInfo, Env<AttrContext> env) {
   1.213 -            this.pt = resultInfo.pt;
   1.214 -            this.inferenceContext = resultInfo.checkContext.inferenceContext();
   1.215 -            this.treeFilter = argsFilter;
   1.216 -            this.env = env;
   1.217 -        }
   1.218 -
   1.219 -        @Override
   1.220 -        public void scan(JCTree tree) {
   1.221 -            if (tree != null && treeFilter.accepts(tree)) {
   1.222 -                super.scan(tree);
   1.223 -            }
   1.224 +        StuckChecker(Type pt, Infer.InferenceContext inferenceContext) {
   1.225 +            this.pt = pt;
   1.226 +            this.inferenceContext = inferenceContext;
   1.227          }
   1.228  
   1.229          @Override
   1.230          public void visitLambda(JCLambda tree) {
   1.231 -            Type prevPt = pt;
   1.232 -            Filter<JCTree> prevFilter = treeFilter;
   1.233 -            try {
   1.234 -                if (inferenceContext.inferenceVars().contains(pt)) {
   1.235 -                    stuckVars.add(pt);
   1.236 -                }
   1.237 -                if (!types.isFunctionalInterface(pt.tsym)) {
   1.238 -                    return;
   1.239 -                }
   1.240 -                Type descType = types.findDescriptorType(pt);
   1.241 -                List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   1.242 -                if (!TreeInfo.isExplicitLambda(tree) &&
   1.243 -                        freeArgVars.nonEmpty()) {
   1.244 -                    stuckVars.addAll(freeArgVars);
   1.245 -                }
   1.246 -                pt = descType.getReturnType();
   1.247 -                if (tree.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
   1.248 -                    scan(tree.getBody());
   1.249 -                } else {
   1.250 -                    treeFilter = lambdaBodyFilter;
   1.251 -                    super.visitLambda(tree);
   1.252 -                }
   1.253 -            } finally {
   1.254 -                pt = prevPt;
   1.255 -                treeFilter = prevFilter;
   1.256 +            if (inferenceContext.inferenceVars().contains(pt)) {
   1.257 +                stuckVars.add(pt);
   1.258              }
   1.259 +            if (!types.isFunctionalInterface(pt.tsym)) {
   1.260 +                return;
   1.261 +            }
   1.262 +            Type descType = types.findDescriptorType(pt);
   1.263 +            List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
   1.264 +            if (!TreeInfo.isExplicitLambda(tree) &&
   1.265 +                    freeArgVars.nonEmpty()) {
   1.266 +                stuckVars.addAll(freeArgVars);
   1.267 +            }
   1.268 +            scanLambdaBody(tree, descType.getReturnType());
   1.269          }
   1.270  
   1.271          @Override
   1.272 @@ -605,16 +652,19 @@
   1.273              stuckVars.addAll(freeArgVars);
   1.274          }
   1.275  
   1.276 -        @Override
   1.277 -        public void visitReturn(JCReturn tree) {
   1.278 -            Filter<JCTree> prevFilter = treeFilter;
   1.279 -            try {
   1.280 -                treeFilter = argsFilter;
   1.281 -                if (tree.expr != null) {
   1.282 -                    scan(tree.expr);
   1.283 -                }
   1.284 -            } finally {
   1.285 -                treeFilter = prevFilter;
   1.286 +        void scanLambdaBody(JCLambda lambda, final Type pt) {
   1.287 +            if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
   1.288 +                stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext));
   1.289 +            } else {
   1.290 +                LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
   1.291 +                    @Override
   1.292 +                    public void visitReturn(JCReturn tree) {
   1.293 +                        if (tree.expr != null) {
   1.294 +                            stuckVars.addAll(stuckVarsInternal(tree.expr, pt, inferenceContext));
   1.295 +                        }
   1.296 +                    }
   1.297 +                };
   1.298 +                lambdaScanner.scan(lambda.body);
   1.299              }
   1.300          }
   1.301      }

mercurial