< prev index next >

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

Print this page
rev 54093 : 8177068: incomplete classpath causes NPE in Flow
Summary: Undo completions that failed during speculative attribution, so that the appropriate CompletionFailures are thrown again and properly reported.
Reviewed-by: vromero


  77  */
  78 public class DeferredAttr extends JCTree.Visitor {
  79     protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
  80 
  81     final Attr attr;
  82     final ArgumentAttr argumentAttr;
  83     final Check chk;
  84     final JCDiagnostic.Factory diags;
  85     final Enter enter;
  86     final Infer infer;
  87     final Resolve rs;
  88     final Log log;
  89     final Symtab syms;
  90     final TreeMaker make;
  91     final TreeCopier<Void> treeCopier;
  92     final TypeMapping<Void> deferredCopier;
  93     final Types types;
  94     final Flow flow;
  95     final Names names;
  96     final TypeEnvs typeEnvs;

  97 
  98     public static DeferredAttr instance(Context context) {
  99         DeferredAttr instance = context.get(deferredAttrKey);
 100         if (instance == null)
 101             instance = new DeferredAttr(context);
 102         return instance;
 103     }
 104 
 105     protected DeferredAttr(Context context) {
 106         context.put(deferredAttrKey, this);
 107         attr = Attr.instance(context);
 108         argumentAttr = ArgumentAttr.instance(context);
 109         chk = Check.instance(context);
 110         diags = JCDiagnostic.Factory.instance(context);
 111         enter = Enter.instance(context);
 112         infer = Infer.instance(context);
 113         rs = Resolve.instance(context);
 114         log = Log.instance(context);
 115         syms = Symtab.instance(context);
 116         make = TreeMaker.instance(context);
 117         types = Types.instance(context);
 118         flow = Flow.instance(context);
 119         names = Names.instance(context);
 120         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
 121         typeEnvs = TypeEnvs.instance(context);

 122         emptyDeferredAttrContext =
 123             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
 124                 @Override
 125                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
 126                     Assert.error("Empty deferred context!");
 127                 }
 128                 @Override
 129                 void complete() {
 130                     Assert.error("Empty deferred context!");
 131                 }
 132 
 133                 @Override
 134                 public String toString() {
 135                     return "Empty deferred context!";
 136                 }
 137             };
 138 
 139         // For speculative attribution, skip the class definition in <>.
 140         treeCopier =
 141             new TreeCopier<Void>(make) {


 462             if (lambdaBody.hasTag(Tag.RETURN)) {
 463                 lambdaBody = ((JCReturn)lambdaBody).expr;
 464             }
 465             JCLambda speculativeLambda = make.Lambda(args, lambdaBody);
 466             attr.preFlow(speculativeLambda);
 467             flow.analyzeLambda(env, speculativeLambda, make, false);
 468             return speculativeLambda;
 469         } finally {
 470             localEnv.info.scope.leave();
 471         }
 472     }
 473 
 474     /**
 475      * Routine that performs speculative type-checking; the input AST node is
 476      * cloned (to avoid side-effects cause by Attr) and compiler state is
 477      * restored after type-checking. All diagnostics (but critical ones) are
 478      * disabled during speculative type-checking.
 479      */
 480     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
 481         return attribSpeculative(tree, env, resultInfo, treeCopier,
 482                 (newTree)->new DeferredAttrDiagHandler(log, newTree), null);
 483     }
 484 
 485     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, LocalCacheContext localCache) {
 486         return attribSpeculative(tree, env, resultInfo, treeCopier,
 487                 (newTree)->new DeferredAttrDiagHandler(log, newTree), localCache);
 488     }
 489 
 490     <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
 491                                  Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator,
 492                                  LocalCacheContext localCache) {
 493         final JCTree newTree = deferredCopier.copy(tree);
 494         Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
 495         speculativeEnv.info.isSpeculative = true;
 496         Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);

 497         try {
 498             attr.attribTree(newTree, speculativeEnv, resultInfo);
 499             return newTree;
 500         } finally {

 501             new UnenterScanner(env.toplevel.modle).scan(newTree);
 502             log.popDiagnosticHandler(deferredDiagnosticHandler);
 503             if (localCache != null) {
 504                 localCache.leave();
 505             }
 506         }
 507     }
 508     //where
 509 
 510         class UnenterScanner extends TreeScanner {
 511             private final ModuleSymbol msym;
 512 
 513             public UnenterScanner(ModuleSymbol msym) {
 514                 this.msym = msym;
 515             }
 516 
 517             @Override
 518             public void visitClassDef(JCClassDecl tree) {
 519                 ClassSymbol csym = tree.sym;
 520                 //if something went wrong during method applicability check
 521                 //it is possible that nested expressions inside argument expression
 522                 //are left unchecked - in such cases there's nothing to clean up.
 523                 if (csym == null) return;
 524                 typeEnvs.remove(csym);
 525                 chk.removeCompiled(csym);
 526                 chk.clearLocalClassNameIndexes(csym);
 527                 syms.removeClass(msym, csym.flatname);
 528                 super.visitClassDef(tree);
 529             }
 530         }
 531 
 532         static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
 533 
 534             static class PosScanner extends TreeScanner {
 535                 DiagnosticPosition pos;
 536                 boolean found = false;
 537 
 538                 PosScanner(DiagnosticPosition pos) {
 539                     this.pos = pos;
 540                 }
 541 
 542                 @Override
 543                 public void scan(JCTree tree) {
 544                     if (tree != null &&
 545                             tree.pos() == pos) {
 546                         found = true;
 547                     }
 548                     super.scan(tree);
 549                 }
 550             }
 551 
 552             DeferredAttrDiagHandler(Log log, JCTree newTree) {
 553                 super(log, d -> {
 554                     PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
 555                     posScanner.scan(newTree);
 556                     return posScanner.found;
 557                 });
 558             }
 559         }
 560 
 561     /**
 562      * A deferred context is created on each method check. A deferred context is
 563      * used to keep track of information associated with the method check, such as
 564      * the symbol of the method being checked, the overload resolution phase,
 565      * the kind of attribution mode to be applied to deferred types and so forth.
 566      * As deferred types are processed (by the method check routine) stuck AST nodes
 567      * are added (as new deferred attribution nodes) to this context. The complete()
 568      * routine makes sure that all pending nodes are properly processed, by
 569      * progressively instantiating all inference variables on which one or more
 570      * deferred attribution node is stuck.
 571      */
 572     class DeferredAttrContext {
 573 
 574         /** attribution mode */
 575         final AttrMode mode;
 576 
 577         /** symbol of the method being checked */




  77  */
  78 public class DeferredAttr extends JCTree.Visitor {
  79     protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
  80 
  81     final Attr attr;
  82     final ArgumentAttr argumentAttr;
  83     final Check chk;
  84     final JCDiagnostic.Factory diags;
  85     final Enter enter;
  86     final Infer infer;
  87     final Resolve rs;
  88     final Log log;
  89     final Symtab syms;
  90     final TreeMaker make;
  91     final TreeCopier<Void> treeCopier;
  92     final TypeMapping<Void> deferredCopier;
  93     final Types types;
  94     final Flow flow;
  95     final Names names;
  96     final TypeEnvs typeEnvs;
  97     final DeferredCompletionFailureHandler dcfh;
  98 
  99     public static DeferredAttr instance(Context context) {
 100         DeferredAttr instance = context.get(deferredAttrKey);
 101         if (instance == null)
 102             instance = new DeferredAttr(context);
 103         return instance;
 104     }
 105 
 106     protected DeferredAttr(Context context) {
 107         context.put(deferredAttrKey, this);
 108         attr = Attr.instance(context);
 109         argumentAttr = ArgumentAttr.instance(context);
 110         chk = Check.instance(context);
 111         diags = JCDiagnostic.Factory.instance(context);
 112         enter = Enter.instance(context);
 113         infer = Infer.instance(context);
 114         rs = Resolve.instance(context);
 115         log = Log.instance(context);
 116         syms = Symtab.instance(context);
 117         make = TreeMaker.instance(context);
 118         types = Types.instance(context);
 119         flow = Flow.instance(context);
 120         names = Names.instance(context);
 121         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
 122         typeEnvs = TypeEnvs.instance(context);
 123         dcfh = DeferredCompletionFailureHandler.instance(context);
 124         emptyDeferredAttrContext =
 125             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
 126                 @Override
 127                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
 128                     Assert.error("Empty deferred context!");
 129                 }
 130                 @Override
 131                 void complete() {
 132                     Assert.error("Empty deferred context!");
 133                 }
 134 
 135                 @Override
 136                 public String toString() {
 137                     return "Empty deferred context!";
 138                 }
 139             };
 140 
 141         // For speculative attribution, skip the class definition in <>.
 142         treeCopier =
 143             new TreeCopier<Void>(make) {


 464             if (lambdaBody.hasTag(Tag.RETURN)) {
 465                 lambdaBody = ((JCReturn)lambdaBody).expr;
 466             }
 467             JCLambda speculativeLambda = make.Lambda(args, lambdaBody);
 468             attr.preFlow(speculativeLambda);
 469             flow.analyzeLambda(env, speculativeLambda, make, false);
 470             return speculativeLambda;
 471         } finally {
 472             localEnv.info.scope.leave();
 473         }
 474     }
 475 
 476     /**
 477      * Routine that performs speculative type-checking; the input AST node is
 478      * cloned (to avoid side-effects cause by Attr) and compiler state is
 479      * restored after type-checking. All diagnostics (but critical ones) are
 480      * disabled during speculative type-checking.
 481      */
 482     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
 483         return attribSpeculative(tree, env, resultInfo, treeCopier,
 484                 newTree->new DeferredDiagnosticHandler(log), null);
 485     }
 486 
 487     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, LocalCacheContext localCache) {
 488         return attribSpeculative(tree, env, resultInfo, treeCopier,
 489                 newTree->new DeferredDiagnosticHandler(log), localCache);
 490     }
 491 
 492     <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
 493                                  Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator,
 494                                  LocalCacheContext localCache) {
 495         final JCTree newTree = deferredCopier.copy(tree);
 496         Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
 497         speculativeEnv.info.isSpeculative = true;
 498         Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);
 499         DeferredCompletionFailureHandler.Handler prevCFHandler = dcfh.setHandler(dcfh.speculativeCodeHandler);
 500         try {
 501             attr.attribTree(newTree, speculativeEnv, resultInfo);
 502             return newTree;
 503         } finally {
 504             dcfh.setHandler(prevCFHandler);
 505             new UnenterScanner(env.toplevel.modle).scan(newTree);
 506             log.popDiagnosticHandler(deferredDiagnosticHandler);
 507             if (localCache != null) {
 508                 localCache.leave();
 509             }
 510         }
 511     }
 512     //where
 513 
 514         class UnenterScanner extends TreeScanner {
 515             private final ModuleSymbol msym;
 516 
 517             public UnenterScanner(ModuleSymbol msym) {
 518                 this.msym = msym;
 519             }
 520 
 521             @Override
 522             public void visitClassDef(JCClassDecl tree) {
 523                 ClassSymbol csym = tree.sym;
 524                 //if something went wrong during method applicability check
 525                 //it is possible that nested expressions inside argument expression
 526                 //are left unchecked - in such cases there's nothing to clean up.
 527                 if (csym == null) return;
 528                 typeEnvs.remove(csym);
 529                 chk.removeCompiled(csym);
 530                 chk.clearLocalClassNameIndexes(csym);
 531                 syms.removeClass(msym, csym.flatname);
 532                 super.visitClassDef(tree);





























 533             }
 534         }
 535 
 536     /**
 537      * A deferred context is created on each method check. A deferred context is
 538      * used to keep track of information associated with the method check, such as
 539      * the symbol of the method being checked, the overload resolution phase,
 540      * the kind of attribution mode to be applied to deferred types and so forth.
 541      * As deferred types are processed (by the method check routine) stuck AST nodes
 542      * are added (as new deferred attribution nodes) to this context. The complete()
 543      * routine makes sure that all pending nodes are properly processed, by
 544      * progressively instantiating all inference variables on which one or more
 545      * deferred attribution node is stuck.
 546      */
 547     class DeferredAttrContext {
 548 
 549         /** attribution mode */
 550         final AttrMode mode;
 551 
 552         /** symbol of the method being checked */


< prev index next >