src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
changeset 52794 e4ba5414c8b4
parent 52635 6938c8ef179a
child 52936 9745e4e36dd1
equal deleted inserted replaced
52793:df065f8356d7 52794:e4ba5414c8b4
   298 
   298 
   299     /**
   299     /**
   300      * Base visitor class for all visitors implementing dataflow analysis logic.
   300      * Base visitor class for all visitors implementing dataflow analysis logic.
   301      * This class define the shared logic for handling jumps (break/continue statements).
   301      * This class define the shared logic for handling jumps (break/continue statements).
   302      */
   302      */
   303     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   303     static abstract class BaseAnalyzer extends TreeScanner {
   304 
   304 
   305         enum JumpKind {
   305         enum JumpKind {
   306             BREAK(JCTree.Tag.BREAK) {
   306             BREAK(JCTree.Tag.BREAK) {
   307                 @Override
   307                 @Override
   308                 JCTree getTarget(JCTree tree) {
   308                 JCTree getTarget(JCTree tree) {
   326         }
   326         }
   327 
   327 
   328         /** The currently pending exits that go from current inner blocks
   328         /** The currently pending exits that go from current inner blocks
   329          *  to an enclosing block, in source order.
   329          *  to an enclosing block, in source order.
   330          */
   330          */
   331         ListBuffer<P> pendingExits;
   331         ListBuffer<PendingExit> pendingExits;
   332 
   332 
   333         /** A pending exit.  These are the statements return, break, and
   333         /** A pending exit.  These are the statements return, break, and
   334          *  continue.  In addition, exception-throwing expressions or
   334          *  continue.  In addition, exception-throwing expressions or
   335          *  statements are put here when not known to be caught.  This
   335          *  statements are put here when not known to be caught.  This
   336          *  will typically result in an error unless it is within a
   336          *  will typically result in an error unless it is within a
   349         }
   349         }
   350 
   350 
   351         abstract void markDead();
   351         abstract void markDead();
   352 
   352 
   353         /** Record an outward transfer of control. */
   353         /** Record an outward transfer of control. */
   354         void recordExit(P pe) {
   354         void recordExit(PendingExit pe) {
   355             pendingExits.append(pe);
   355             pendingExits.append(pe);
   356             markDead();
   356             markDead();
   357         }
   357         }
   358 
   358 
   359         /** Resolve all jumps of this statement. */
   359         /** Resolve all jumps of this statement. */
   360         private Liveness resolveJump(JCTree tree,
   360         private Liveness resolveJump(JCTree tree,
   361                          ListBuffer<P> oldPendingExits,
   361                          ListBuffer<PendingExit> oldPendingExits,
   362                          JumpKind jk) {
   362                          JumpKind jk) {
   363             boolean resolved = false;
   363             boolean resolved = false;
   364             List<P> exits = pendingExits.toList();
   364             List<PendingExit> exits = pendingExits.toList();
   365             pendingExits = oldPendingExits;
   365             pendingExits = oldPendingExits;
   366             for (; exits.nonEmpty(); exits = exits.tail) {
   366             for (; exits.nonEmpty(); exits = exits.tail) {
   367                 P exit = exits.head;
   367                 PendingExit exit = exits.head;
   368                 if (exit.tree.hasTag(jk.treeTag) &&
   368                 if (exit.tree.hasTag(jk.treeTag) &&
   369                         jk.getTarget(exit.tree) == tree) {
   369                         jk.getTarget(exit.tree) == tree) {
   370                     exit.resolveJump();
   370                     exit.resolveJump();
   371                     resolved = true;
   371                     resolved = true;
   372                 } else {
   372                 } else {
   376             return Liveness.from(resolved);
   376             return Liveness.from(resolved);
   377         }
   377         }
   378 
   378 
   379         /** Resolve all continues of this statement. */
   379         /** Resolve all continues of this statement. */
   380         Liveness resolveContinues(JCTree tree) {
   380         Liveness resolveContinues(JCTree tree) {
   381             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   381             return resolveJump(tree, new ListBuffer<PendingExit>(), JumpKind.CONTINUE);
   382         }
   382         }
   383 
   383 
   384         /** Resolve all breaks of this statement. */
   384         /** Resolve all breaks of this statement. */
   385         Liveness resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   385         Liveness resolveBreaks(JCTree tree, ListBuffer<PendingExit> oldPendingExits) {
   386             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   386             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   387         }
   387         }
   388 
   388 
   389         @Override
   389         @Override
   390         public void scan(JCTree tree) {
   390         public void scan(JCTree tree) {
   410      * This pass implements the first step of the dataflow analysis, namely
   410      * This pass implements the first step of the dataflow analysis, namely
   411      * the liveness analysis check. This checks that every statement is reachable.
   411      * the liveness analysis check. This checks that every statement is reachable.
   412      * The output of this analysis pass are used by other analyzers. This analyzer
   412      * The output of this analysis pass are used by other analyzers. This analyzer
   413      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   413      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   414      */
   414      */
   415     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   415     class AliveAnalyzer extends BaseAnalyzer {
   416 
   416 
   417         /** A flag that indicates whether the last statement could
   417         /** A flag that indicates whether the last statement could
   418          *  complete normally.
   418          *  complete normally.
   419          */
   419          */
   420         private Liveness alive;
   420         private Liveness alive;
   829      * This pass implements the second step of the dataflow analysis, namely
   829      * This pass implements the second step of the dataflow analysis, namely
   830      * the exception analysis. This is to ensure that every checked exception that is
   830      * the exception analysis. This is to ensure that every checked exception that is
   831      * thrown is declared or caught. The analyzer uses some info that has been set by
   831      * thrown is declared or caught. The analyzer uses some info that has been set by
   832      * the liveliness analyzer.
   832      * the liveliness analyzer.
   833      */
   833      */
   834     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   834     class FlowAnalyzer extends BaseAnalyzer {
   835 
   835 
   836         /** A flag that indicates whether the last statement could
   836         /** A flag that indicates whether the last statement could
   837          *  complete normally.
   837          *  complete normally.
   838          */
   838          */
   839         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   839         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   849         /** The list of exceptions that are either caught or declared to be
   849         /** The list of exceptions that are either caught or declared to be
   850          *  thrown.
   850          *  thrown.
   851          */
   851          */
   852         List<Type> caught;
   852         List<Type> caught;
   853 
   853 
   854         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   854         class ThrownPendingExit extends BaseAnalyzer.PendingExit {
   855 
   855 
   856             Type thrown;
   856             Type thrown;
   857 
   857 
   858             FlowPendingExit(JCTree tree, Type thrown) {
   858             ThrownPendingExit(JCTree tree, Type thrown) {
   859                 super(tree);
   859                 super(tree);
   860                 this.thrown = thrown;
   860                 this.thrown = thrown;
   861             }
   861             }
   862         }
   862         }
   863 
   863 
   869         /*-------------------- Exceptions ----------------------*/
   869         /*-------------------- Exceptions ----------------------*/
   870 
   870 
   871         /** Complain that pending exceptions are not caught.
   871         /** Complain that pending exceptions are not caught.
   872          */
   872          */
   873         void errorUncaught() {
   873         void errorUncaught() {
   874             for (FlowPendingExit exit = pendingExits.next();
   874             for (PendingExit exit = pendingExits.next();
   875                  exit != null;
   875                  exit != null;
   876                  exit = pendingExits.next()) {
   876                  exit = pendingExits.next()) {
       
   877                 Assert.check(exit instanceof ThrownPendingExit);
       
   878                 ThrownPendingExit thrownExit = (ThrownPendingExit) exit;
   877                 if (classDef != null &&
   879                 if (classDef != null &&
   878                     classDef.pos == exit.tree.pos) {
   880                     classDef.pos == exit.tree.pos) {
   879                     log.error(exit.tree.pos(),
   881                     log.error(exit.tree.pos(),
   880                               Errors.UnreportedExceptionDefaultConstructor(exit.thrown));
   882                               Errors.UnreportedExceptionDefaultConstructor(thrownExit.thrown));
   881                 } else if (exit.tree.hasTag(VARDEF) &&
   883                 } else if (exit.tree.hasTag(VARDEF) &&
   882                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   884                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   883                     log.error(exit.tree.pos(),
   885                     log.error(exit.tree.pos(),
   884                               Errors.UnreportedExceptionImplicitClose(exit.thrown,
   886                               Errors.UnreportedExceptionImplicitClose(thrownExit.thrown,
   885                                                                       ((JCVariableDecl)exit.tree).sym.name));
   887                                                                       ((JCVariableDecl)exit.tree).sym.name));
   886                 } else {
   888                 } else {
   887                     log.error(exit.tree.pos(),
   889                     log.error(exit.tree.pos(),
   888                               Errors.UnreportedExceptionNeedToCatchOrThrow(exit.thrown));
   890                               Errors.UnreportedExceptionNeedToCatchOrThrow(thrownExit.thrown));
   889                 }
   891                 }
   890             }
   892             }
   891         }
   893         }
   892 
   894 
   893         /** Record that exception is potentially thrown and check that it
   895         /** Record that exception is potentially thrown and check that it
   894          *  is caught.
   896          *  is caught.
   895          */
   897          */
   896         void markThrown(JCTree tree, Type exc) {
   898         void markThrown(JCTree tree, Type exc) {
   897             if (!chk.isUnchecked(tree.pos(), exc)) {
   899             if (!chk.isUnchecked(tree.pos(), exc)) {
   898                 if (!chk.isHandled(exc, caught)) {
   900                 if (!chk.isHandled(exc, caught)) {
   899                     pendingExits.append(new FlowPendingExit(tree, exc));
   901                     pendingExits.append(new ThrownPendingExit(tree, exc));
   900                 }
   902                 }
   901                 thrown = chk.incl(exc, thrown);
   903                 thrown = chk.incl(exc, thrown);
   902             }
   904             }
   903         }
   905         }
   904 
   906 
   912             if (tree.sym == null) return;
   914             if (tree.sym == null) return;
   913 
   915 
   914             JCClassDecl classDefPrev = classDef;
   916             JCClassDecl classDefPrev = classDef;
   915             List<Type> thrownPrev = thrown;
   917             List<Type> thrownPrev = thrown;
   916             List<Type> caughtPrev = caught;
   918             List<Type> caughtPrev = caught;
   917             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   919             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   918             Lint lintPrev = lint;
   920             Lint lintPrev = lint;
   919             boolean anonymousClass = tree.name == names.empty;
   921             boolean anonymousClass = tree.name == names.empty;
   920             pendingExits = new ListBuffer<>();
   922             pendingExits = new ListBuffer<>();
   921             if (!anonymousClass) {
   923             if (!anonymousClass) {
   922                 caught = List.nil();
   924                 caught = List.nil();
  1022                 // else we are in an instance initializer block;
  1024                 // else we are in an instance initializer block;
  1023                 // leave caught unchanged.
  1025                 // leave caught unchanged.
  1024 
  1026 
  1025                 scan(tree.body);
  1027                 scan(tree.body);
  1026 
  1028 
  1027                 List<FlowPendingExit> exits = pendingExits.toList();
  1029                 List<PendingExit> exits = pendingExits.toList();
  1028                 pendingExits = new ListBuffer<>();
  1030                 pendingExits = new ListBuffer<>();
  1029                 while (exits.nonEmpty()) {
  1031                 while (exits.nonEmpty()) {
  1030                     FlowPendingExit exit = exits.head;
  1032                     PendingExit exit = exits.head;
  1031                     exits = exits.tail;
  1033                     exits = exits.tail;
  1032                     if (exit.thrown == null) {
  1034                     if (!(exit instanceof ThrownPendingExit)) {
  1033                         Assert.check(exit.tree.hasTag(RETURN));
  1035                         Assert.check(exit.tree.hasTag(RETURN));
  1034                     } else {
  1036                     } else {
  1035                         // uncaught throws will be reported later
  1037                         // uncaught throws will be reported later
  1036                         pendingExits.append(exit);
  1038                         pendingExits.append(exit);
  1037                     }
  1039                     }
  1057         public void visitBlock(JCBlock tree) {
  1059         public void visitBlock(JCBlock tree) {
  1058             scan(tree.stats);
  1060             scan(tree.stats);
  1059         }
  1061         }
  1060 
  1062 
  1061         public void visitDoLoop(JCDoWhileLoop tree) {
  1063         public void visitDoLoop(JCDoWhileLoop tree) {
  1062             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1064             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1063             pendingExits = new ListBuffer<>();
  1065             pendingExits = new ListBuffer<>();
  1064             scan(tree.body);
  1066             scan(tree.body);
  1065             resolveContinues(tree);
  1067             resolveContinues(tree);
  1066             scan(tree.cond);
  1068             scan(tree.cond);
  1067             resolveBreaks(tree, prevPendingExits);
  1069             resolveBreaks(tree, prevPendingExits);
  1068         }
  1070         }
  1069 
  1071 
  1070         public void visitWhileLoop(JCWhileLoop tree) {
  1072         public void visitWhileLoop(JCWhileLoop tree) {
  1071             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1073             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1072             pendingExits = new ListBuffer<>();
  1074             pendingExits = new ListBuffer<>();
  1073             scan(tree.cond);
  1075             scan(tree.cond);
  1074             scan(tree.body);
  1076             scan(tree.body);
  1075             resolveContinues(tree);
  1077             resolveContinues(tree);
  1076             resolveBreaks(tree, prevPendingExits);
  1078             resolveBreaks(tree, prevPendingExits);
  1077         }
  1079         }
  1078 
  1080 
  1079         public void visitForLoop(JCForLoop tree) {
  1081         public void visitForLoop(JCForLoop tree) {
  1080             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1082             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1081             scan(tree.init);
  1083             scan(tree.init);
  1082             pendingExits = new ListBuffer<>();
  1084             pendingExits = new ListBuffer<>();
  1083             if (tree.cond != null) {
  1085             if (tree.cond != null) {
  1084                 scan(tree.cond);
  1086                 scan(tree.cond);
  1085             }
  1087             }
  1089             resolveBreaks(tree, prevPendingExits);
  1091             resolveBreaks(tree, prevPendingExits);
  1090         }
  1092         }
  1091 
  1093 
  1092         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1094         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1093             visitVarDef(tree.var);
  1095             visitVarDef(tree.var);
  1094             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1096             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1095             scan(tree.expr);
  1097             scan(tree.expr);
  1096             pendingExits = new ListBuffer<>();
  1098             pendingExits = new ListBuffer<>();
  1097             scan(tree.body);
  1099             scan(tree.body);
  1098             resolveContinues(tree);
  1100             resolveContinues(tree);
  1099             resolveBreaks(tree, prevPendingExits);
  1101             resolveBreaks(tree, prevPendingExits);
  1100         }
  1102         }
  1101 
  1103 
  1102         public void visitLabelled(JCLabeledStatement tree) {
  1104         public void visitLabelled(JCLabeledStatement tree) {
  1103             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1105             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1104             pendingExits = new ListBuffer<>();
  1106             pendingExits = new ListBuffer<>();
  1105             scan(tree.body);
  1107             scan(tree.body);
  1106             resolveBreaks(tree, prevPendingExits);
  1108             resolveBreaks(tree, prevPendingExits);
  1107         }
  1109         }
  1108 
  1110 
  1114         public void visitSwitchExpression(JCSwitchExpression tree) {
  1116         public void visitSwitchExpression(JCSwitchExpression tree) {
  1115             handleSwitch(tree, tree.selector, tree.cases);
  1117             handleSwitch(tree, tree.selector, tree.cases);
  1116         }
  1118         }
  1117 
  1119 
  1118         private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
  1120         private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
  1119             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1121             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1120             pendingExits = new ListBuffer<>();
  1122             pendingExits = new ListBuffer<>();
  1121             scan(selector);
  1123             scan(selector);
  1122             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
  1124             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
  1123                 JCCase c = l.head;
  1125                 JCCase c = l.head;
  1124                 scan(c.pats);
  1126                 scan(c.pats);
  1138                 for (JCExpression ct : subClauses) {
  1140                 for (JCExpression ct : subClauses) {
  1139                     caught = chk.incl(ct.type, caught);
  1141                     caught = chk.incl(ct.type, caught);
  1140                 }
  1142                 }
  1141             }
  1143             }
  1142 
  1144 
  1143             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1145             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1144             pendingExits = new ListBuffer<>();
  1146             pendingExits = new ListBuffer<>();
  1145             for (JCTree resource : tree.resources) {
  1147             for (JCTree resource : tree.resources) {
  1146                 if (resource instanceof JCVariableDecl) {
  1148                 if (resource instanceof JCVariableDecl) {
  1147                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1149                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1148                     visitVarDef(vdecl);
  1150                     visitVarDef(vdecl);
  1202                 preciseRethrowTypes.remove(param.sym);
  1204                 preciseRethrowTypes.remove(param.sym);
  1203             }
  1205             }
  1204             if (tree.finalizer != null) {
  1206             if (tree.finalizer != null) {
  1205                 List<Type> savedThrown = thrown;
  1207                 List<Type> savedThrown = thrown;
  1206                 thrown = List.nil();
  1208                 thrown = List.nil();
  1207                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1209                 ListBuffer<PendingExit> exits = pendingExits;
  1208                 pendingExits = prevPendingExits;
  1210                 pendingExits = prevPendingExits;
  1209                 scan(tree.finalizer);
  1211                 scan(tree.finalizer);
  1210                 if (!tree.finallyCanCompleteNormally) {
  1212                 if (!tree.finallyCanCompleteNormally) {
  1211                     // discard exits and exceptions from try and finally
  1213                     // discard exits and exceptions from try and finally
  1212                     thrown = chk.union(thrown, thrownPrev);
  1214                     thrown = chk.union(thrown, thrownPrev);
  1219                         pendingExits.append(exits.next());
  1221                         pendingExits.append(exits.next());
  1220                     }
  1222                     }
  1221                 }
  1223                 }
  1222             } else {
  1224             } else {
  1223                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1225                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1224                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1226                 ListBuffer<PendingExit> exits = pendingExits;
  1225                 pendingExits = prevPendingExits;
  1227                 pendingExits = prevPendingExits;
  1226                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1228                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1227             }
  1229             }
  1228         }
  1230         }
  1229 
  1231 
  1265             }
  1267             }
  1266 
  1268 
  1267         public void visitBreak(JCBreak tree) {
  1269         public void visitBreak(JCBreak tree) {
  1268             if (tree.isValueBreak())
  1270             if (tree.isValueBreak())
  1269                 scan(tree.value);
  1271                 scan(tree.value);
  1270             recordExit(new FlowPendingExit(tree, null));
  1272             recordExit(new PendingExit(tree));
  1271         }
  1273         }
  1272 
  1274 
  1273         public void visitContinue(JCContinue tree) {
  1275         public void visitContinue(JCContinue tree) {
  1274             recordExit(new FlowPendingExit(tree, null));
  1276             recordExit(new PendingExit(tree));
  1275         }
  1277         }
  1276 
  1278 
  1277         public void visitReturn(JCReturn tree) {
  1279         public void visitReturn(JCReturn tree) {
  1278             scan(tree.expr);
  1280             scan(tree.expr);
  1279             recordExit(new FlowPendingExit(tree, null));
  1281             recordExit(new PendingExit(tree));
  1280         }
  1282         }
  1281 
  1283 
  1282         public void visitThrow(JCThrow tree) {
  1284         public void visitThrow(JCThrow tree) {
  1283             scan(tree.expr);
  1285             scan(tree.expr);
  1284             Symbol sym = TreeInfo.symbol(tree.expr);
  1286             Symbol sym = TreeInfo.symbol(tree.expr);
  1341                     tree.type.isErroneous()) {
  1343                     tree.type.isErroneous()) {
  1342                 return;
  1344                 return;
  1343             }
  1345             }
  1344             List<Type> prevCaught = caught;
  1346             List<Type> prevCaught = caught;
  1345             List<Type> prevThrown = thrown;
  1347             List<Type> prevThrown = thrown;
  1346             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1348             ListBuffer<PendingExit> prevPending = pendingExits;
  1347             try {
  1349             try {
  1348                 pendingExits = new ListBuffer<>();
  1350                 pendingExits = new ListBuffer<>();
  1349                 caught = tree.getDescriptorType(types).getThrownTypes();
  1351                 caught = tree.getDescriptorType(types).getThrownTypes();
  1350                 thrown = List.nil();
  1352                 thrown = List.nil();
  1351                 scan(tree.body);
  1353                 scan(tree.body);
  1352                 List<FlowPendingExit> exits = pendingExits.toList();
  1354                 List<PendingExit> exits = pendingExits.toList();
  1353                 pendingExits = new ListBuffer<>();
  1355                 pendingExits = new ListBuffer<>();
  1354                 while (exits.nonEmpty()) {
  1356                 while (exits.nonEmpty()) {
  1355                     FlowPendingExit exit = exits.head;
  1357                     PendingExit exit = exits.head;
  1356                     exits = exits.tail;
  1358                     exits = exits.tail;
  1357                     if (exit.thrown == null) {
  1359                     if (!(exit instanceof ThrownPendingExit)) {
  1358                         Assert.check(exit.tree.hasTag(RETURN));
  1360                         Assert.check(exit.tree.hasTag(RETURN));
  1359                     } else {
  1361                     } else {
  1360                         // uncaught throws will be reported later
  1362                         // uncaught throws will be reported later
  1361                         pendingExits.append(exit);
  1363                         pendingExits.append(exit);
  1362                     }
  1364                     }
  1486                     tree.type.isErroneous()) || inLambda) {
  1488                     tree.type.isErroneous()) || inLambda) {
  1487                 return;
  1489                 return;
  1488             }
  1490             }
  1489             List<Type> prevCaught = caught;
  1491             List<Type> prevCaught = caught;
  1490             List<Type> prevThrown = thrown;
  1492             List<Type> prevThrown = thrown;
  1491             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1493             ListBuffer<PendingExit> prevPending = pendingExits;
  1492             inLambda = true;
  1494             inLambda = true;
  1493             try {
  1495             try {
  1494                 pendingExits = new ListBuffer<>();
  1496                 pendingExits = new ListBuffer<>();
  1495                 caught = List.of(syms.throwableType);
  1497                 caught = List.of(syms.throwableType);
  1496                 thrown = List.nil();
  1498                 thrown = List.nil();
  1515      * which ensures that no final variable is assigned more than once. This visitor
  1517      * which ensures that no final variable is assigned more than once. This visitor
  1516      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1518      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1517      * effectively-final local variables/parameters.
  1519      * effectively-final local variables/parameters.
  1518      */
  1520      */
  1519 
  1521 
  1520     public class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1522     public class AssignAnalyzer extends BaseAnalyzer {
  1521 
  1523 
  1522         /** The set of definitely assigned variables.
  1524         /** The set of definitely assigned variables.
  1523          */
  1525          */
  1524         final Bits inits;
  1526         final Bits inits;
  1525 
  1527 
  1833                 }
  1835                 }
  1834 
  1836 
  1835                 JCClassDecl classDefPrev = classDef;
  1837                 JCClassDecl classDefPrev = classDef;
  1836                 int firstadrPrev = firstadr;
  1838                 int firstadrPrev = firstadr;
  1837                 int nextadrPrev = nextadr;
  1839                 int nextadrPrev = nextadr;
  1838                 ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
  1840                 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
  1839 
  1841 
  1840                 pendingExits = new ListBuffer<>();
  1842                 pendingExits = new ListBuffer<>();
  1841                 if (tree.name != names.empty) {
  1843                 if (tree.name != names.empty) {
  1842                     firstadr = nextadr;
  1844                     firstadr = nextadr;
  1843                 }
  1845                 }
  1968                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
  1970                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
  1969                                 }
  1971                                 }
  1970                             }
  1972                             }
  1971                         }
  1973                         }
  1972                     }
  1974                     }
  1973                     List<AssignPendingExit> exits = pendingExits.toList();
  1975                     List<PendingExit> exits = pendingExits.toList();
  1974                     pendingExits = new ListBuffer<>();
  1976                     pendingExits = new ListBuffer<>();
  1975                     while (exits.nonEmpty()) {
  1977                     while (exits.nonEmpty()) {
  1976                         AssignPendingExit exit = exits.head;
  1978                         PendingExit exit = exits.head;
  1977                         exits = exits.tail;
  1979                         exits = exits.tail;
  1978                         Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1980                         Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1979                         if (isInitialConstructor) {
  1981                         if (isInitialConstructor) {
  1980                             inits.assign(exit.exit_inits);
  1982                             Assert.check(exit instanceof AssignPendingExit);
       
  1983                             inits.assign(((AssignPendingExit) exit).exit_inits);
  1981                             for (int i = firstadr; i < nextadr; i++) {
  1984                             for (int i = firstadr; i < nextadr; i++) {
  1982                                 checkInit(exit.tree.pos(), vardecls[i].sym);
  1985                                 checkInit(exit.tree.pos(), vardecls[i].sym);
  1983                             }
  1986                             }
  1984                         }
  1987                         }
  1985                     }
  1988                     }
  2025             scan(tree.stats);
  2028             scan(tree.stats);
  2026             nextadr = nextadrPrev;
  2029             nextadr = nextadrPrev;
  2027         }
  2030         }
  2028 
  2031 
  2029         public void visitDoLoop(JCDoWhileLoop tree) {
  2032         public void visitDoLoop(JCDoWhileLoop tree) {
  2030             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2033             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  2031             FlowKind prevFlowKind = flowKind;
  2034             FlowKind prevFlowKind = flowKind;
  2032             flowKind = FlowKind.NORMAL;
  2035             flowKind = FlowKind.NORMAL;
  2033             final Bits initsSkip = new Bits(true);
  2036             final Bits initsSkip = new Bits(true);
  2034             final Bits uninitsSkip = new Bits(true);
  2037             final Bits uninitsSkip = new Bits(true);
  2035             pendingExits = new ListBuffer<>();
  2038             pendingExits = new ListBuffer<>();
  2057             uninits.assign(uninitsSkip);
  2060             uninits.assign(uninitsSkip);
  2058             resolveBreaks(tree, prevPendingExits);
  2061             resolveBreaks(tree, prevPendingExits);
  2059         }
  2062         }
  2060 
  2063 
  2061         public void visitWhileLoop(JCWhileLoop tree) {
  2064         public void visitWhileLoop(JCWhileLoop tree) {
  2062             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2065             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  2063             FlowKind prevFlowKind = flowKind;
  2066             FlowKind prevFlowKind = flowKind;
  2064             flowKind = FlowKind.NORMAL;
  2067             flowKind = FlowKind.NORMAL;
  2065             final Bits initsSkip = new Bits(true);
  2068             final Bits initsSkip = new Bits(true);
  2066             final Bits uninitsSkip = new Bits(true);
  2069             final Bits uninitsSkip = new Bits(true);
  2067             pendingExits = new ListBuffer<>();
  2070             pendingExits = new ListBuffer<>();
  2093             uninits.assign(uninitsSkip);
  2096             uninits.assign(uninitsSkip);
  2094             resolveBreaks(tree, prevPendingExits);
  2097             resolveBreaks(tree, prevPendingExits);
  2095         }
  2098         }
  2096 
  2099 
  2097         public void visitForLoop(JCForLoop tree) {
  2100         public void visitForLoop(JCForLoop tree) {
  2098             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2101             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  2099             FlowKind prevFlowKind = flowKind;
  2102             FlowKind prevFlowKind = flowKind;
  2100             flowKind = FlowKind.NORMAL;
  2103             flowKind = FlowKind.NORMAL;
  2101             int nextadrPrev = nextadr;
  2104             int nextadrPrev = nextadr;
  2102             scan(tree.init);
  2105             scan(tree.init);
  2103             final Bits initsSkip = new Bits(true);
  2106             final Bits initsSkip = new Bits(true);
  2141         }
  2144         }
  2142 
  2145 
  2143         public void visitForeachLoop(JCEnhancedForLoop tree) {
  2146         public void visitForeachLoop(JCEnhancedForLoop tree) {
  2144             visitVarDef(tree.var);
  2147             visitVarDef(tree.var);
  2145 
  2148 
  2146             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2149             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  2147             FlowKind prevFlowKind = flowKind;
  2150             FlowKind prevFlowKind = flowKind;
  2148             flowKind = FlowKind.NORMAL;
  2151             flowKind = FlowKind.NORMAL;
  2149             int nextadrPrev = nextadr;
  2152             int nextadrPrev = nextadr;
  2150             scan(tree.expr);
  2153             scan(tree.expr);
  2151             final Bits initsStart = new Bits(inits);
  2154             final Bits initsStart = new Bits(inits);
  2172             resolveBreaks(tree, prevPendingExits);
  2175             resolveBreaks(tree, prevPendingExits);
  2173             nextadr = nextadrPrev;
  2176             nextadr = nextadrPrev;
  2174         }
  2177         }
  2175 
  2178 
  2176         public void visitLabelled(JCLabeledStatement tree) {
  2179         public void visitLabelled(JCLabeledStatement tree) {
  2177             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2180             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  2178             pendingExits = new ListBuffer<>();
  2181             pendingExits = new ListBuffer<>();
  2179             scan(tree.body);
  2182             scan(tree.body);
  2180             resolveBreaks(tree, prevPendingExits);
  2183             resolveBreaks(tree, prevPendingExits);
  2181         }
  2184         }
  2182 
  2185 
  2187         public void visitSwitchExpression(JCSwitchExpression tree) {
  2190         public void visitSwitchExpression(JCSwitchExpression tree) {
  2188             handleSwitch(tree, tree.selector, tree.cases);
  2191             handleSwitch(tree, tree.selector, tree.cases);
  2189         }
  2192         }
  2190 
  2193 
  2191         private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
  2194         private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
  2192             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2195             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  2193             pendingExits = new ListBuffer<>();
  2196             pendingExits = new ListBuffer<>();
  2194             int nextadrPrev = nextadr;
  2197             int nextadrPrev = nextadr;
  2195             scanExpr(selector);
  2198             scanExpr(selector);
  2196             final Bits initsSwitch = new Bits(inits);
  2199             final Bits initsSwitch = new Bits(inits);
  2197             final Bits uninitsSwitch = new Bits(uninits);
  2200             final Bits uninitsSwitch = new Bits(uninits);
  2243             }
  2246             }
  2244 
  2247 
  2245         public void visitTry(JCTry tree) {
  2248         public void visitTry(JCTry tree) {
  2246             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
  2249             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
  2247             final Bits uninitsTryPrev = new Bits(uninitsTry);
  2250             final Bits uninitsTryPrev = new Bits(uninitsTry);
  2248             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2251             ListBuffer<PendingExit> prevPendingExits = pendingExits;
  2249             pendingExits = new ListBuffer<>();
  2252             pendingExits = new ListBuffer<>();
  2250             final Bits initsTry = new Bits(inits);
  2253             final Bits initsTry = new Bits(inits);
  2251             uninitsTry.assign(uninits);
  2254             uninitsTry.assign(uninits);
  2252             for (JCTree resource : tree.resources) {
  2255             for (JCTree resource : tree.resources) {
  2253                 if (resource instanceof JCVariableDecl) {
  2256                 if (resource instanceof JCVariableDecl) {
  2300                 nextadr = nextadrCatch;
  2303                 nextadr = nextadrCatch;
  2301             }
  2304             }
  2302             if (tree.finalizer != null) {
  2305             if (tree.finalizer != null) {
  2303                 inits.assign(initsTry);
  2306                 inits.assign(initsTry);
  2304                 uninits.assign(uninitsTry);
  2307                 uninits.assign(uninitsTry);
  2305                 ListBuffer<AssignPendingExit> exits = pendingExits;
  2308                 ListBuffer<PendingExit> exits = pendingExits;
  2306                 pendingExits = prevPendingExits;
  2309                 pendingExits = prevPendingExits;
  2307                 scan(tree.finalizer);
  2310                 scan(tree.finalizer);
  2308                 if (!tree.finallyCanCompleteNormally) {
  2311                 if (!tree.finallyCanCompleteNormally) {
  2309                     // discard exits and exceptions from try and finally
  2312                     // discard exits and exceptions from try and finally
  2310                 } else {
  2313                 } else {
  2311                     uninits.andSet(uninitsEnd);
  2314                     uninits.andSet(uninitsEnd);
  2312                     // FIX: this doesn't preserve source order of exits in catch
  2315                     // FIX: this doesn't preserve source order of exits in catch
  2313                     // versus finally!
  2316                     // versus finally!
  2314                     while (exits.nonEmpty()) {
  2317                     while (exits.nonEmpty()) {
  2315                         AssignPendingExit exit = exits.next();
  2318                         PendingExit exit = exits.next();
  2316                         if (exit.exit_inits != null) {
  2319                         if (exit instanceof AssignPendingExit) {
  2317                             exit.exit_inits.orSet(inits);
  2320                             ((AssignPendingExit) exit).exit_inits.orSet(inits);
  2318                             exit.exit_uninits.andSet(uninits);
  2321                             ((AssignPendingExit) exit).exit_uninits.andSet(uninits);
  2319                         }
  2322                         }
  2320                         pendingExits.append(exit);
  2323                         pendingExits.append(exit);
  2321                     }
  2324                     }
  2322                     inits.orSet(initsEnd);
  2325                     inits.orSet(initsEnd);
  2323                 }
  2326                 }
  2324             } else {
  2327             } else {
  2325                 inits.assign(initsEnd);
  2328                 inits.assign(initsEnd);
  2326                 uninits.assign(uninitsEnd);
  2329                 uninits.assign(uninitsEnd);
  2327                 ListBuffer<AssignPendingExit> exits = pendingExits;
  2330                 ListBuffer<PendingExit> exits = pendingExits;
  2328                 pendingExits = prevPendingExits;
  2331                 pendingExits = prevPendingExits;
  2329                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  2332                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  2330             }
  2333             }
  2331             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  2334             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  2332         }
  2335         }
  2388             }
  2391             }
  2389         }
  2392         }
  2390 
  2393 
  2391         @Override
  2394         @Override
  2392         public void visitBreak(JCBreak tree) {
  2395         public void visitBreak(JCBreak tree) {
  2393             if (tree.isValueBreak())
  2396             if (tree.isValueBreak()) {
       
  2397                 if (tree.target.hasTag(SWITCH_EXPRESSION)) {
       
  2398                     JCSwitchExpression expr = (JCSwitchExpression) tree.target;
       
  2399                     if (expr.type.hasTag(BOOLEAN)) {
       
  2400                         scanCond(tree.value);
       
  2401                         Bits initsAfterBreakWhenTrue = new Bits(initsWhenTrue);
       
  2402                         Bits initsAfterBreakWhenFalse = new Bits(initsWhenFalse);
       
  2403                         Bits uninitsAfterBreakWhenTrue = new Bits(uninitsWhenTrue);
       
  2404                         Bits uninitsAfterBreakWhenFalse = new Bits(uninitsWhenFalse);
       
  2405                         PendingExit exit = new PendingExit(tree) {
       
  2406                             @Override
       
  2407                             void resolveJump() {
       
  2408                                 if (!inits.isReset()) {
       
  2409                                     split(true);
       
  2410                                 }
       
  2411                                 initsWhenTrue.andSet(initsAfterBreakWhenTrue);
       
  2412                                 initsWhenFalse.andSet(initsAfterBreakWhenFalse);
       
  2413                                 uninitsWhenTrue.andSet(uninitsAfterBreakWhenTrue);
       
  2414                                 uninitsWhenFalse.andSet(uninitsAfterBreakWhenFalse);
       
  2415                             }
       
  2416                         };
       
  2417                         merge();
       
  2418                         recordExit(exit);
       
  2419                         return ;
       
  2420                     }
       
  2421                 }
  2394                 scan(tree.value);
  2422                 scan(tree.value);
       
  2423             }
  2395             recordExit(new AssignPendingExit(tree, inits, uninits));
  2424             recordExit(new AssignPendingExit(tree, inits, uninits));
  2396         }
  2425         }
  2397 
  2426 
  2398         @Override
  2427         @Override
  2399         public void visitContinue(JCContinue tree) {
  2428         public void visitContinue(JCContinue tree) {
  2426         public void visitLambda(JCLambda tree) {
  2455         public void visitLambda(JCLambda tree) {
  2427             final Bits prevUninits = new Bits(uninits);
  2456             final Bits prevUninits = new Bits(uninits);
  2428             final Bits prevInits = new Bits(inits);
  2457             final Bits prevInits = new Bits(inits);
  2429             int returnadrPrev = returnadr;
  2458             int returnadrPrev = returnadr;
  2430             int nextadrPrev = nextadr;
  2459             int nextadrPrev = nextadr;
  2431             ListBuffer<AssignPendingExit> prevPending = pendingExits;
  2460             ListBuffer<PendingExit> prevPending = pendingExits;
  2432             try {
  2461             try {
  2433                 returnadr = nextadr;
  2462                 returnadr = nextadr;
  2434                 pendingExits = new ListBuffer<>();
  2463                 pendingExits = new ListBuffer<>();
  2435                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2464                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2436                     JCVariableDecl def = l.head;
  2465                     JCVariableDecl def = l.head;
  2616      * Additional this also checks that every variable that is used as an operand to
  2645      * Additional this also checks that every variable that is used as an operand to
  2617      * try-with-resources is final or effectively final.
  2646      * try-with-resources is final or effectively final.
  2618      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2647      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2619      * AssignAnalyzer.
  2648      * AssignAnalyzer.
  2620      */
  2649      */
  2621     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2650     class CaptureAnalyzer extends BaseAnalyzer {
  2622 
  2651 
  2623         JCTree currentTree; //local class or lambda
  2652         JCTree currentTree; //local class or lambda
  2624 
  2653 
  2625         @Override
  2654         @Override
  2626         void markDead() {
  2655         void markDead() {