# HG changeset patch # User mcimadamore # Date 1357636649 -3600 # Node ID 80190ab051c02d25caf6ed2304aa36c48728a779 # Parent 3ad27d268874374b10bce7cc02c952d6e0f45c1e 8005184: Restructure DeferredAttr to allow pluggable deferred type completers Summary: Add hooks to generalize deferred type completion via custom helper objects Reviewed-by: jjg diff -r 3ad27d268874 -r 80190ab051c0 langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Tue Jan 08 10:16:26 2013 +0100 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Tue Jan 08 10:17:29 2013 +0100 @@ -38,6 +38,7 @@ import javax.tools.JavaFileObject; import java.util.ArrayList; +import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Queue; @@ -177,29 +178,19 @@ * attribution round must follow one or more speculative rounds. */ Type check(ResultInfo resultInfo) { + return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter); + } + + Type check(ResultInfo resultInfo, List stuckVars, DeferredTypeCompleter deferredTypeCompleter) { DeferredAttrContext deferredAttrContext = resultInfo.checkContext.deferredAttrContext(); Assert.check(deferredAttrContext != emptyDeferredAttrContext); - List stuckVars = stuckVars(tree, env, resultInfo); if (stuckVars.nonEmpty()) { deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars); return Type.noType; } else { try { - switch (deferredAttrContext.mode) { - case SPECULATIVE: - Assert.check(mode == null || - (mode == AttrMode.SPECULATIVE && - speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE))); - JCTree speculativeTree = attribSpeculative(tree, env, resultInfo); - speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase); - return speculativeTree.type; - case CHECK: - Assert.check(mode == AttrMode.SPECULATIVE); - return attr.attribTree(tree, env, resultInfo); - } - Assert.error(); - return null; + return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext); } finally { mode = deferredAttrContext.mode; } @@ -208,6 +199,43 @@ } /** + * A completer for deferred types. Defines an entry point for type-checking + * a deferred type. + */ + interface DeferredTypeCompleter { + /** + * Entry point for type-checking a deferred type. Depending on the + * circumstances, type-checking could amount to full attribution + * or partial structural check (aka potential applicability). + */ + Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext); + } + + /** + * A basic completer for deferred types. This completer type-checks a deferred type + * using attribution; depending on the attribution mode, this could be either standard + * or speculative attribution. + */ + DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() { + public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { + switch (deferredAttrContext.mode) { + case SPECULATIVE: + Assert.check(dt.mode == null || + (dt.mode == AttrMode.SPECULATIVE && + dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE))); + JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo); + dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase); + return speculativeTree.type; + case CHECK: + Assert.check(dt.mode == AttrMode.SPECULATIVE); + return attr.attribTree(dt.tree, dt.env, resultInfo); + } + Assert.error(); + return null; + } + }; + + /** * The 'mode' in which the deferred type is to be type-checked */ public enum AttrMode { @@ -498,10 +526,80 @@ if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) { return List.nil(); } else { - StuckChecker sc = new StuckChecker(resultInfo, env); + return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext()); + } + } + //where + private List stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) { + StuckChecker sc = new StuckChecker(pt, inferenceContext); sc.scan(tree); return List.from(sc.stuckVars); } + + /** + * A special tree scanner that would only visit portions of a given tree. + * The set of nodes visited by the scanner can be customized at construction-time. + */ + abstract static class FilterScanner extends TreeScanner { + + final Filter treeFilter; + + FilterScanner(final Set validTags) { + this.treeFilter = new Filter() { + public boolean accepts(JCTree t) { + return validTags.contains(t.getTag()); + } + }; + } + + @Override + public void scan(JCTree tree) { + if (tree != null) { + if (treeFilter.accepts(tree)) { + super.scan(tree); + } else { + skip(tree); + } + } + } + + /** + * handler that is executed when a node has been discarded + */ + abstract void skip(JCTree tree); + } + + /** + * A tree scanner suitable for visiting the target-type dependent nodes of + * a given argument expression. + */ + static class PolyScanner extends FilterScanner { + + PolyScanner() { + super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE)); + } + + @Override + void skip(JCTree tree) { + //do nothing + } + } + + /** + * A tree scanner suitable for visiting the target-type dependent nodes nested + * within a lambda expression body. + */ + static class LambdaReturnScanner extends FilterScanner { + + LambdaReturnScanner() { + super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP, + FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP)); + } + + @Override + void skip(JCTree tree) { + //do nothing + } } /** @@ -510,83 +608,32 @@ * inferring types that make some of the nested expressions incompatible * with their corresponding instantiated target */ - class StuckChecker extends TreeScanner { + class StuckChecker extends PolyScanner { Type pt; - Filter treeFilter; Infer.InferenceContext inferenceContext; Set stuckVars = new LinkedHashSet(); - Env env; - final Filter argsFilter = new Filter() { - public boolean accepts(JCTree t) { - switch (t.getTag()) { - case CONDEXPR: - case LAMBDA: - case PARENS: - case REFERENCE: - return true; - default: - return false; - } - } - }; - - final Filter lambdaBodyFilter = new Filter() { - public boolean accepts(JCTree t) { - switch (t.getTag()) { - case BLOCK: case CASE: case CATCH: case DOLOOP: - case FOREACHLOOP: case FORLOOP: case RETURN: - case SYNCHRONIZED: case SWITCH: case TRY: case WHILELOOP: - return true; - default: - return false; - } - } - }; - - StuckChecker(ResultInfo resultInfo, Env env) { - this.pt = resultInfo.pt; - this.inferenceContext = resultInfo.checkContext.inferenceContext(); - this.treeFilter = argsFilter; - this.env = env; - } - - @Override - public void scan(JCTree tree) { - if (tree != null && treeFilter.accepts(tree)) { - super.scan(tree); - } + StuckChecker(Type pt, Infer.InferenceContext inferenceContext) { + this.pt = pt; + this.inferenceContext = inferenceContext; } @Override public void visitLambda(JCLambda tree) { - Type prevPt = pt; - Filter prevFilter = treeFilter; - try { - if (inferenceContext.inferenceVars().contains(pt)) { - stuckVars.add(pt); - } - if (!types.isFunctionalInterface(pt.tsym)) { - return; - } - Type descType = types.findDescriptorType(pt); - List freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); - if (!TreeInfo.isExplicitLambda(tree) && - freeArgVars.nonEmpty()) { - stuckVars.addAll(freeArgVars); - } - pt = descType.getReturnType(); - if (tree.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { - scan(tree.getBody()); - } else { - treeFilter = lambdaBodyFilter; - super.visitLambda(tree); - } - } finally { - pt = prevPt; - treeFilter = prevFilter; + if (inferenceContext.inferenceVars().contains(pt)) { + stuckVars.add(pt); + } + if (!types.isFunctionalInterface(pt.tsym)) { + return; } + Type descType = types.findDescriptorType(pt); + List freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); + if (!TreeInfo.isExplicitLambda(tree) && + freeArgVars.nonEmpty()) { + stuckVars.addAll(freeArgVars); + } + scanLambdaBody(tree, descType.getReturnType()); } @Override @@ -605,16 +652,19 @@ stuckVars.addAll(freeArgVars); } - @Override - public void visitReturn(JCReturn tree) { - Filter prevFilter = treeFilter; - try { - treeFilter = argsFilter; - if (tree.expr != null) { - scan(tree.expr); - } - } finally { - treeFilter = prevFilter; + void scanLambdaBody(JCLambda lambda, final Type pt) { + if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { + stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext)); + } else { + LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() { + @Override + public void visitReturn(JCReturn tree) { + if (tree.expr != null) { + stuckVars.addAll(stuckVarsInternal(tree.expr, pt, inferenceContext)); + } + } + }; + lambdaScanner.scan(lambda.body); } } }