1 /*
   2  * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.Map;
  31 import java.util.Map.Entry;
  32 import java.util.HashMap;
  33 import java.util.HashSet;
  34 import java.util.Set;
  35 
  36 import com.sun.source.tree.CaseTree;
  37 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
  38 import com.sun.tools.javac.code.*;
  39 import com.sun.tools.javac.code.Scope.WriteableScope;
  40 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  41 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  42 import com.sun.tools.javac.tree.*;
  43 import com.sun.tools.javac.util.*;
  44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  45 import com.sun.tools.javac.util.JCDiagnostic.Error;
  46 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  47 
  48 import com.sun.tools.javac.code.Symbol.*;
  49 import com.sun.tools.javac.tree.JCTree.*;
  50 
  51 import static com.sun.tools.javac.code.Flags.*;
  52 import static com.sun.tools.javac.code.Flags.BLOCK;
  53 import com.sun.tools.javac.code.Kinds.Kind;
  54 import static com.sun.tools.javac.code.Kinds.Kind.*;
  55 import com.sun.tools.javac.code.Type.TypeVar;
  56 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  57 import static com.sun.tools.javac.code.TypeTag.VOID;
  58 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  61 import java.util.Arrays;
  62 import java.util.Collections;
  63 import java.util.IdentityHashMap;
  64 import java.util.Iterator;
  65 import java.util.function.Predicate;
  66 import java.util.stream.Collectors;
  67 
  68 import static java.util.stream.Collectors.groupingBy;
  69 
  70 /** This pass implements dataflow analysis for Java programs though
  71  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  72  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  73  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  74  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  75  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  76  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  77  *  determines that local variables accessed within the scope of an inner class/lambda
  78  *  are either final or effectively-final.
  79  *
  80  *  <p>The JLS has a number of problems in the
  81  *  specification of these flow analysis problems. This implementation
  82  *  attempts to address those issues.
  83  *
  84  *  <p>First, there is no accommodation for a finally clause that cannot
  85  *  complete normally. For liveness analysis, an intervening finally
  86  *  clause can cause a break, continue, or return not to reach its
  87  *  target.  For exception analysis, an intervening finally clause can
  88  *  cause any exception to be "caught".  For DA/DU analysis, the finally
  89  *  clause can prevent a transfer of control from propagating DA/DU
  90  *  state to the target.  In addition, code in the finally clause can
  91  *  affect the DA/DU status of variables.
  92  *
  93  *  <p>For try statements, we introduce the idea of a variable being
  94  *  definitely unassigned "everywhere" in a block.  A variable V is
  95  *  "unassigned everywhere" in a block iff it is unassigned at the
  96  *  beginning of the block and there is no reachable assignment to V
  97  *  in the block.  An assignment V=e is reachable iff V is not DA
  98  *  after e.  Then we can say that V is DU at the beginning of the
  99  *  catch block iff V is DU everywhere in the try block.  Similarly, V
 100  *  is DU at the beginning of the finally block iff V is DU everywhere
 101  *  in the try block and in every catch block.  Specifically, the
 102  *  following bullet is added to 16.2.2
 103  *  <pre>
 104  *      V is <em>unassigned everywhere</em> in a block if it is
 105  *      unassigned before the block and there is no reachable
 106  *      assignment to V within the block.
 107  *  </pre>
 108  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
 109  *  try blocks is changed to
 110  *  <pre>
 111  *      V is definitely unassigned before a catch block iff V is
 112  *      definitely unassigned everywhere in the try block.
 113  *  </pre>
 114  *  <p>The last bullet (and all of its sub-bullets) for try blocks that
 115  *  have a finally block is changed to
 116  *  <pre>
 117  *      V is definitely unassigned before the finally block iff
 118  *      V is definitely unassigned everywhere in the try block
 119  *      and everywhere in each catch block of the try statement.
 120  *  </pre>
 121  *  <p>In addition,
 122  *  <pre>
 123  *      V is definitely assigned at the end of a constructor iff
 124  *      V is definitely assigned after the block that is the body
 125  *      of the constructor and V is definitely assigned at every
 126  *      return that can return from the constructor.
 127  *  </pre>
 128  *  <p>In addition, each continue statement with the loop as its target
 129  *  is treated as a jump to the end of the loop body, and "intervening"
 130  *  finally clauses are treated as follows: V is DA "due to the
 131  *  continue" iff V is DA before the continue statement or V is DA at
 132  *  the end of any intervening finally block.  V is DU "due to the
 133  *  continue" iff any intervening finally cannot complete normally or V
 134  *  is DU at the end of every intervening finally block.  This "due to
 135  *  the continue" concept is then used in the spec for the loops.
 136  *
 137  *  <p>Similarly, break statements must consider intervening finally
 138  *  blocks.  For liveness analysis, a break statement for which any
 139  *  intervening finally cannot complete normally is not considered to
 140  *  cause the target statement to be able to complete normally. Then
 141  *  we say V is DA "due to the break" iff V is DA before the break or
 142  *  V is DA at the end of any intervening finally block.  V is DU "due
 143  *  to the break" iff any intervening finally cannot complete normally
 144  *  or V is DU at the break and at the end of every intervening
 145  *  finally block.  (I suspect this latter condition can be
 146  *  simplified.)  This "due to the break" is then used in the spec for
 147  *  all statements that can be "broken".
 148  *
 149  *  <p>The return statement is treated similarly.  V is DA "due to a
 150  *  return statement" iff V is DA before the return statement or V is
 151  *  DA at the end of any intervening finally block.  Note that we
 152  *  don't have to worry about the return expression because this
 153  *  concept is only used for constructors.
 154  *
 155  *  <p>There is no spec in the JLS for when a variable is definitely
 156  *  assigned at the end of a constructor, which is needed for final
 157  *  fields (8.3.1.2).  We implement the rule that V is DA at the end
 158  *  of the constructor iff it is DA and the end of the body of the
 159  *  constructor and V is DA "due to" every return of the constructor.
 160  *
 161  *  <p>Intervening finally blocks similarly affect exception analysis.  An
 162  *  intervening finally that cannot complete normally allows us to ignore
 163  *  an otherwise uncaught exception.
 164  *
 165  *  <p>To implement the semantics of intervening finally clauses, all
 166  *  nonlocal transfers (break, continue, return, throw, method call that
 167  *  can throw a checked exception, and a constructor invocation that can
 168  *  thrown a checked exception) are recorded in a queue, and removed
 169  *  from the queue when we complete processing the target of the
 170  *  nonlocal transfer.  This allows us to modify the queue in accordance
 171  *  with the above rules when we encounter a finally clause.  The only
 172  *  exception to this [no pun intended] is that checked exceptions that
 173  *  are known to be caught or declared to be caught in the enclosing
 174  *  method are not recorded in the queue, but instead are recorded in a
 175  *  global variable "{@code Set<Type> thrown}" that records the type of all
 176  *  exceptions that can be thrown.
 177  *
 178  *  <p>Other minor issues the treatment of members of other classes
 179  *  (always considered DA except that within an anonymous class
 180  *  constructor, where DA status from the enclosing scope is
 181  *  preserved), treatment of the case expression (V is DA before the
 182  *  case expression iff V is DA after the switch expression),
 183  *  treatment of variables declared in a switch block (the implied
 184  *  DA/DU status after the switch expression is DU and not DA for
 185  *  variables defined in a switch block), the treatment of boolean ?:
 186  *  expressions (The JLS rules only handle b and c non-boolean; the
 187  *  new rule is that if b and c are boolean valued, then V is
 188  *  (un)assigned after a?b:c when true/false iff V is (un)assigned
 189  *  after b when true/false and V is (un)assigned after c when
 190  *  true/false).
 191  *
 192  *  <p>There is the remaining question of what syntactic forms constitute a
 193  *  reference to a variable.  It is conventional to allow this.x on the
 194  *  left-hand-side to initialize a final instance field named x, yet
 195  *  this.x isn't considered a "use" when appearing on a right-hand-side
 196  *  in most implementations.  Should parentheses affect what is
 197  *  considered a variable reference?  The simplest rule would be to
 198  *  allow unqualified forms only, parentheses optional, and phase out
 199  *  support for assigning to a final field via this.x.
 200  *
 201  *  <p><b>This is NOT part of any supported API.
 202  *  If you write code that depends on this, you do so at your own risk.
 203  *  This code and its internal interfaces are subject to change or
 204  *  deletion without notice.</b>
 205  */
 206 public class Flow {
 207     protected static final Context.Key<Flow> flowKey = new Context.Key<>();
 208 
 209     private final Names names;
 210     private final Log log;
 211     private final Symtab syms;
 212     private final Types types;
 213     private final Check chk;
 214     private       TreeMaker make;
 215     private final Resolve rs;
 216     private final JCDiagnostic.Factory diags;
 217     private Env<AttrContext> attrEnv;
 218     private       Lint lint;
 219     private final Infer infer;
 220 
 221     public static Flow instance(Context context) {
 222         Flow instance = context.get(flowKey);
 223         if (instance == null)
 224             instance = new Flow(context);
 225         return instance;
 226     }
 227 
 228     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 229         new AliveAnalyzer().analyzeTree(env, make);
 230         new AssignAnalyzer().analyzeTree(env, make);
 231         new FlowAnalyzer().analyzeTree(env, make);
 232         new CaptureAnalyzer().analyzeTree(env, make);
 233         new ThisEscapeAnalyzer(names, syms, types, log, lint).analyzeTree(env);
 234     }
 235 
 236     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
 237         Log.DiagnosticHandler diagHandler = null;
 238         //we need to disable diagnostics temporarily; the problem is that if
 239         //a lambda expression contains e.g. an unreachable statement, an error
 240         //message will be reported and will cause compilation to skip the flow analysis
 241         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 242         //related errors, which will allow for more errors to be detected
 243         if (!speculative) {
 244             diagHandler = new Log.DiscardDiagnosticHandler(log);
 245         }
 246         try {
 247             new LambdaAliveAnalyzer().analyzeTree(env, that, make);
 248         } finally {
 249             if (!speculative) {
 250                 log.popDiagnosticHandler(diagHandler);
 251             }
 252         }
 253     }
 254 
 255     public List<Type> analyzeLambdaThrownTypes(final Env<AttrContext> env,
 256             JCLambda that, TreeMaker make) {
 257         //we need to disable diagnostics temporarily; the problem is that if
 258         //a lambda expression contains e.g. an unreachable statement, an error
 259         //message will be reported and will cause compilation to skip the flow analysis
 260         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 261         //related errors, which will allow for more errors to be detected
 262         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 263         try {
 264             new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
 265             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
 266             flowAnalyzer.analyzeTree(env, that, make);
 267             return flowAnalyzer.inferredThrownTypes;
 268         } finally {
 269             log.popDiagnosticHandler(diagHandler);
 270         }
 271     }
 272 
 273     public boolean aliveAfter(Env<AttrContext> env, JCTree that, TreeMaker make) {
 274         //we need to disable diagnostics temporarily; the problem is that if
 275         //"that" contains e.g. an unreachable statement, an error
 276         //message will be reported and will cause compilation to skip the flow analysis
 277         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 278         //related errors, which will allow for more errors to be detected
 279         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 280         try {
 281             SnippetAliveAnalyzer analyzer = new SnippetAliveAnalyzer();
 282 
 283             analyzer.analyzeTree(env, that, make);
 284             return analyzer.isAlive();
 285         } finally {
 286             log.popDiagnosticHandler(diagHandler);
 287         }
 288     }
 289 
 290     public boolean breaksToTree(Env<AttrContext> env, JCTree breakTo, JCTree body, TreeMaker make) {
 291         //we need to disable diagnostics temporarily; the problem is that if
 292         //"that" contains e.g. an unreachable statement, an error
 293         //message will be reported and will cause compilation to skip the flow analysis
 294         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 295         //related errors, which will allow for more errors to be detected
 296         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 297         try {
 298             SnippetBreakToAnalyzer analyzer = new SnippetBreakToAnalyzer(breakTo);
 299 
 300             analyzer.analyzeTree(env, body, make);
 301             return analyzer.breaksTo();
 302         } finally {
 303             log.popDiagnosticHandler(diagHandler);
 304         }
 305     }
 306 
 307     /**
 308      * Definite assignment scan mode
 309      */
 310     enum FlowKind {
 311         /**
 312          * This is the normal DA/DU analysis mode
 313          */
 314         NORMAL("var.might.already.be.assigned", false),
 315         /**
 316          * This is the speculative DA/DU analysis mode used to speculatively
 317          * derive assertions within loop bodies
 318          */
 319         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
 320 
 321         final String errKey;
 322         final boolean isFinal;
 323 
 324         FlowKind(String errKey, boolean isFinal) {
 325             this.errKey = errKey;
 326             this.isFinal = isFinal;
 327         }
 328 
 329         boolean isFinal() {
 330             return isFinal;
 331         }
 332     }
 333 
 334     @SuppressWarnings("this-escape")
 335     protected Flow(Context context) {
 336         context.put(flowKey, this);
 337         names = Names.instance(context);
 338         log = Log.instance(context);
 339         syms = Symtab.instance(context);
 340         types = Types.instance(context);
 341         chk = Check.instance(context);
 342         lint = Lint.instance(context);
 343         infer = Infer.instance(context);
 344         rs = Resolve.instance(context);
 345         diags = JCDiagnostic.Factory.instance(context);
 346         Source source = Source.instance(context);
 347     }
 348 
 349     /**
 350      * Base visitor class for all visitors implementing dataflow analysis logic.
 351      * This class define the shared logic for handling jumps (break/continue statements).
 352      */
 353     abstract static class BaseAnalyzer extends TreeScanner {
 354 
 355         enum JumpKind {
 356             BREAK(JCTree.Tag.BREAK) {
 357                 @Override
 358                 JCTree getTarget(JCTree tree) {
 359                     return ((JCBreak)tree).target;
 360                 }
 361             },
 362             CONTINUE(JCTree.Tag.CONTINUE) {
 363                 @Override
 364                 JCTree getTarget(JCTree tree) {
 365                     return ((JCContinue)tree).target;
 366                 }
 367             },
 368             YIELD(JCTree.Tag.YIELD) {
 369                 @Override
 370                 JCTree getTarget(JCTree tree) {
 371                     return ((JCYield)tree).target;
 372                 }
 373             };
 374 
 375             final JCTree.Tag treeTag;
 376 
 377             private JumpKind(Tag treeTag) {
 378                 this.treeTag = treeTag;
 379             }
 380 
 381             abstract JCTree getTarget(JCTree tree);
 382         }
 383 
 384         /** The currently pending exits that go from current inner blocks
 385          *  to an enclosing block, in source order.
 386          */
 387         ListBuffer<PendingExit> pendingExits;
 388 
 389         /** A pending exit.  These are the statements return, break, and
 390          *  continue.  In addition, exception-throwing expressions or
 391          *  statements are put here when not known to be caught.  This
 392          *  will typically result in an error unless it is within a
 393          *  try-finally whose finally block cannot complete normally.
 394          */
 395         static class PendingExit {
 396             JCTree tree;
 397 
 398             PendingExit(JCTree tree) {
 399                 this.tree = tree;
 400             }
 401 
 402             void resolveJump() {
 403                 //do nothing
 404             }
 405         }
 406 
 407         abstract void markDead();
 408 
 409         /** Record an outward transfer of control. */
 410         void recordExit(PendingExit pe) {
 411             pendingExits.append(pe);
 412             markDead();
 413         }
 414 
 415         /** Resolve all jumps of this statement. */
 416         private Liveness resolveJump(JCTree tree,
 417                          ListBuffer<PendingExit> oldPendingExits,
 418                          JumpKind jk) {
 419             boolean resolved = false;
 420             List<PendingExit> exits = pendingExits.toList();
 421             pendingExits = oldPendingExits;
 422             for (; exits.nonEmpty(); exits = exits.tail) {
 423                 PendingExit exit = exits.head;
 424                 if (exit.tree.hasTag(jk.treeTag) &&
 425                         jk.getTarget(exit.tree) == tree) {
 426                     exit.resolveJump();
 427                     resolved = true;
 428                 } else {
 429                     pendingExits.append(exit);
 430                 }
 431             }
 432             return Liveness.from(resolved);
 433         }
 434 
 435         /** Resolve all continues of this statement. */
 436         Liveness resolveContinues(JCTree tree) {
 437             return resolveJump(tree, new ListBuffer<PendingExit>(), JumpKind.CONTINUE);
 438         }
 439 
 440         /** Resolve all breaks of this statement. */
 441         Liveness resolveBreaks(JCTree tree, ListBuffer<PendingExit> oldPendingExits) {
 442             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
 443         }
 444 
 445         /** Resolve all yields of this statement. */
 446         Liveness resolveYields(JCTree tree, ListBuffer<PendingExit> oldPendingExits) {
 447             return resolveJump(tree, oldPendingExits, JumpKind.YIELD);
 448         }
 449 
 450         @Override
 451         public void scan(JCTree tree) {
 452             if (tree != null && (
 453                     tree.type == null ||
 454                     tree.type != Type.stuckType)) {
 455                 super.scan(tree);
 456             }
 457         }
 458 
 459         public void visitPackageDef(JCPackageDecl tree) {
 460             // Do nothing for PackageDecl
 461         }
 462 
 463         protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
 464             if (swtch.hasTag(SWITCH_EXPRESSION)) {
 465                 JCYield brk = make.at(Position.NOPOS).Yield(null);
 466                 brk.target = swtch;
 467                 scan(brk);
 468             } else {
 469                 JCBreak brk = make.at(Position.NOPOS).Break(null);
 470                 brk.target = swtch;
 471                 scan(brk);
 472             }
 473         }
 474     }
 475 
 476     /**
 477      * This pass implements the first step of the dataflow analysis, namely
 478      * the liveness analysis check. This checks that every statement is reachable.
 479      * The output of this analysis pass are used by other analyzers. This analyzer
 480      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
 481      */
 482     class AliveAnalyzer extends BaseAnalyzer {
 483 
 484         /** A flag that indicates whether the last statement could
 485          *  complete normally.
 486          */
 487         private Liveness alive;
 488 
 489         @Override
 490         void markDead() {
 491             alive = Liveness.DEAD;
 492         }
 493 
 494     /*************************************************************************
 495      * Visitor methods for statements and definitions
 496      *************************************************************************/
 497 
 498         /** Analyze a definition.
 499          */
 500         void scanDef(JCTree tree) {
 501             scanStat(tree);
 502             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && alive == Liveness.DEAD) {
 503                 log.error(tree.pos(),
 504                           Errors.InitializerMustBeAbleToCompleteNormally);
 505             }
 506         }
 507 
 508         /** Analyze a statement. Check that statement is reachable.
 509          */
 510         void scanStat(JCTree tree) {
 511             if (alive == Liveness.DEAD && tree != null) {
 512                 log.error(tree.pos(), Errors.UnreachableStmt);
 513                 if (!tree.hasTag(SKIP)) alive = Liveness.RECOVERY;
 514             }
 515             scan(tree);
 516         }
 517 
 518         /** Analyze list of statements.
 519          */
 520         void scanStats(List<? extends JCStatement> trees) {
 521             if (trees != null)
 522                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
 523                     scanStat(l.head);
 524         }
 525 
 526         /* ------------ Visitor methods for various sorts of trees -------------*/
 527 
 528         public void visitClassDef(JCClassDecl tree) {
 529             if (tree.sym == null) return;
 530             Liveness alivePrev = alive;
 531             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
 532             Lint lintPrev = lint;
 533 
 534             pendingExits = new ListBuffer<>();
 535             lint = lint.augment(tree.sym);
 536 
 537             try {
 538                 // process all the static initializers
 539                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 540                     if (!l.head.hasTag(METHODDEF) &&
 541                         (TreeInfo.flags(l.head) & STATIC) != 0) {
 542                         scanDef(l.head);
 543                         clearPendingExits(false);
 544                     }
 545                 }
 546 
 547                 // process all the instance initializers
 548                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 549                     if (!l.head.hasTag(METHODDEF) &&
 550                         (TreeInfo.flags(l.head) & STATIC) == 0) {
 551                         scanDef(l.head);
 552                         clearPendingExits(false);
 553                     }
 554                 }
 555 
 556                 // process all the methods
 557                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 558                     if (l.head.hasTag(METHODDEF)) {
 559                         scan(l.head);
 560                     }
 561                 }
 562             } finally {
 563                 pendingExits = pendingExitsPrev;
 564                 alive = alivePrev;
 565                 lint = lintPrev;
 566             }
 567         }
 568 
 569         public void visitMethodDef(JCMethodDecl tree) {
 570             if (tree.body == null) return;
 571             Lint lintPrev = lint;
 572 
 573             lint = lint.augment(tree.sym);
 574 
 575             Assert.check(pendingExits.isEmpty());
 576 
 577             try {
 578                 alive = Liveness.ALIVE;
 579                 scanStat(tree.body);
 580                 tree.completesNormally = alive != Liveness.DEAD;
 581 
 582                 if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID))
 583                     log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt);
 584 
 585                 clearPendingExits(true);
 586             } finally {
 587                 lint = lintPrev;
 588             }
 589         }
 590 
 591         private void clearPendingExits(boolean inMethod) {
 592             List<PendingExit> exits = pendingExits.toList();
 593             pendingExits = new ListBuffer<>();
 594             while (exits.nonEmpty()) {
 595                 PendingExit exit = exits.head;
 596                 exits = exits.tail;
 597                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
 598                                 log.hasErrorOn(exit.tree.pos()));
 599             }
 600         }
 601 
 602         public void visitVarDef(JCVariableDecl tree) {
 603             if (tree.init != null) {
 604                 Lint lintPrev = lint;
 605                 lint = lint.augment(tree.sym);
 606                 try{
 607                     scan(tree.init);
 608                 } finally {
 609                     lint = lintPrev;
 610                 }
 611             }
 612         }
 613 
 614         public void visitBlock(JCBlock tree) {
 615             scanStats(tree.stats);
 616         }
 617 
 618         public void visitDoLoop(JCDoWhileLoop tree) {
 619             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 620             pendingExits = new ListBuffer<>();
 621             scanStat(tree.body);
 622             alive = alive.or(resolveContinues(tree));
 623             scan(tree.cond);
 624             alive = alive.and(!tree.cond.type.isTrue());
 625             alive = alive.or(resolveBreaks(tree, prevPendingExits));
 626         }
 627 
 628         public void visitWhileLoop(JCWhileLoop tree) {
 629             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 630             pendingExits = new ListBuffer<>();
 631             scan(tree.cond);
 632             alive = Liveness.from(!tree.cond.type.isFalse());
 633             scanStat(tree.body);
 634             alive = alive.or(resolveContinues(tree));
 635             alive = resolveBreaks(tree, prevPendingExits).or(
 636                 !tree.cond.type.isTrue());
 637         }
 638 
 639         public void visitForLoop(JCForLoop tree) {
 640             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 641             scanStats(tree.init);
 642             pendingExits = new ListBuffer<>();
 643             if (tree.cond != null) {
 644                 scan(tree.cond);
 645                 alive = Liveness.from(!tree.cond.type.isFalse());
 646             } else {
 647                 alive = Liveness.ALIVE;
 648             }
 649             scanStat(tree.body);
 650             alive = alive.or(resolveContinues(tree));
 651             scan(tree.step);
 652             alive = resolveBreaks(tree, prevPendingExits).or(
 653                 tree.cond != null && !tree.cond.type.isTrue());
 654         }
 655 
 656         public void visitForeachLoop(JCEnhancedForLoop tree) {
 657             visitVarDef(tree.var);
 658             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 659             scan(tree.expr);
 660             pendingExits = new ListBuffer<>();
 661             scanStat(tree.body);
 662             alive = alive.or(resolveContinues(tree));
 663             resolveBreaks(tree, prevPendingExits);
 664             alive = Liveness.ALIVE;
 665         }
 666 
 667         public void visitLabelled(JCLabeledStatement tree) {
 668             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 669             pendingExits = new ListBuffer<>();
 670             scanStat(tree.body);
 671             alive = alive.or(resolveBreaks(tree, prevPendingExits));
 672         }
 673 
 674         public void visitSwitch(JCSwitch tree) {
 675             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 676             pendingExits = new ListBuffer<>();
 677             scan(tree.selector);
 678             boolean exhaustiveSwitch = TreeInfo.expectedExhaustive(tree);
 679             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
 680                 alive = Liveness.ALIVE;
 681                 JCCase c = l.head;
 682                 for (JCCaseLabel pat : c.labels) {
 683                     scan(pat);
 684                 }
 685                 scanStats(c.stats);
 686                 if (alive != Liveness.DEAD && c.caseKind == JCCase.RULE) {
 687                     scanSyntheticBreak(make, tree);
 688                     alive = Liveness.DEAD;
 689                 }
 690                 // Warn about fall-through if lint switch fallthrough enabled.
 691                 if (alive == Liveness.ALIVE &&
 692                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
 693                     c.stats.nonEmpty() && l.tail.nonEmpty())
 694                     log.warning(Lint.LintCategory.FALLTHROUGH,
 695                                 l.tail.head.pos(),
 696                                 Warnings.PossibleFallThroughIntoCase);
 697             }
 698             tree.isExhaustive = tree.hasUnconditionalPattern ||
 699                                 TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases);
 700             if (exhaustiveSwitch) {
 701                 tree.isExhaustive |= exhausts(tree.selector, tree.cases);
 702                 if (!tree.isExhaustive) {
 703                     log.error(tree, Errors.NotExhaustiveStatement);
 704                 }
 705             }
 706             if (!tree.hasUnconditionalPattern && !exhaustiveSwitch) {
 707                 alive = Liveness.ALIVE;
 708             }
 709             alive = alive.or(resolveBreaks(tree, prevPendingExits));
 710         }
 711 
 712         @Override
 713         public void visitSwitchExpression(JCSwitchExpression tree) {
 714             ListBuffer<PendingExit> prevPendingExits = pendingExits;
 715             pendingExits = new ListBuffer<>();
 716             scan(tree.selector);
 717             Liveness prevAlive = alive;
 718             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
 719                 alive = Liveness.ALIVE;
 720                 JCCase c = l.head;
 721                 for (JCCaseLabel pat : c.labels) {
 722                     scan(pat);
 723                 }
 724                 scanStats(c.stats);
 725                 if (alive == Liveness.ALIVE) {
 726                     if (c.caseKind == JCCase.RULE) {
 727                         log.error(TreeInfo.diagEndPos(c.body),
 728                                   Errors.RuleCompletesNormally);
 729                     } else if (l.tail.isEmpty()) {
 730                         log.error(TreeInfo.diagEndPos(tree),
 731                                   Errors.SwitchExpressionCompletesNormally);
 732                     }
 733                 }
 734             }
 735             tree.isExhaustive = tree.hasUnconditionalPattern ||
 736                                 TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) ||
 737                                 exhausts(tree.selector, tree.cases);
 738             if (!tree.isExhaustive) {
 739                 log.error(tree, Errors.NotExhaustive);
 740             }
 741             alive = prevAlive;
 742             alive = alive.or(resolveYields(tree, prevPendingExits));
 743         }
 744 
 745         private boolean exhausts(JCExpression selector, List<JCCase> cases) {
 746             Set<PatternDescription> patternSet = new HashSet<>();
 747             Map<Symbol, Set<Symbol>> enum2Constants = new HashMap<>();
 748             for (JCCase c : cases) {
 749                 if (!TreeInfo.unguardedCase(c))
 750                     continue;
 751 
 752                 for (var l : c.labels) {
 753                     if (l instanceof JCPatternCaseLabel patternLabel) {
 754                         for (Type component : components(selector.type)) {
 755                             patternSet.add(makePatternDescription(component, patternLabel.pat));
 756                         }
 757                     } else if (l instanceof JCConstantCaseLabel constantLabel) {
 758                         Symbol s = TreeInfo.symbol(constantLabel.expr);
 759                         if (s != null && s.isEnum()) {
 760                             enum2Constants.computeIfAbsent(s.owner, x -> {
 761                                 Set<Symbol> result = new HashSet<>();
 762                                 s.owner.members()
 763                                        .getSymbols(sym -> sym.kind == Kind.VAR && sym.isEnum())
 764                                        .forEach(result::add);
 765                                 return result;
 766                             }).remove(s);
 767                         }
 768                     }
 769                 }
 770             }
 771             for (Entry<Symbol, Set<Symbol>> e : enum2Constants.entrySet()) {
 772                 if (e.getValue().isEmpty()) {
 773                     patternSet.add(new BindingPattern(e.getKey().type));
 774                 }
 775             }
 776             Set<PatternDescription> patterns = patternSet;
 777             try {
 778                 boolean repeat = true;
 779                 while (repeat) {
 780                     Set<PatternDescription> updatedPatterns;
 781                     updatedPatterns = reduceBindingPatterns(selector.type, patterns);
 782                     updatedPatterns = reduceNestedPatterns(updatedPatterns);
 783                     updatedPatterns = reduceRecordPatterns(updatedPatterns);
 784                     updatedPatterns = removeCoveredRecordPatterns(updatedPatterns);
 785                     repeat = !updatedPatterns.equals(patterns);
 786                     patterns = updatedPatterns;
 787                     if (checkCovered(selector.type, patterns)) {
 788                         return true;
 789                     }
 790                 }
 791                 return checkCovered(selector.type, patterns);
 792             } catch (CompletionFailure cf) {
 793                 chk.completionError(selector.pos(), cf);
 794                 return true; //error recovery
 795             }
 796         }
 797 
 798         private boolean checkCovered(Type seltype, Iterable<PatternDescription> patterns) {
 799             for (Type seltypeComponent : components(seltype)) {
 800                 for (PatternDescription pd : patterns) {
 801                     if (pd instanceof BindingPattern bp &&
 802                         types.isSubtype(seltypeComponent, types.erasure(bp.type))) {
 803                         return true;
 804                     }
 805                 }
 806             }
 807             return false;
 808         }
 809 
 810         private List<Type> components(Type seltype) {
 811             return switch (seltype.getTag()) {
 812                 case CLASS -> {
 813                     if (seltype.isCompound()) {
 814                         if (seltype.isIntersection()) {
 815                             yield ((Type.IntersectionClassType) seltype).getComponents()
 816                                                                         .stream()
 817                                                                         .flatMap(t -> components(t).stream())
 818                                                                         .collect(List.collector());
 819                         }
 820                         yield List.nil();
 821                     }
 822                     yield List.of(types.erasure(seltype));
 823                 }
 824                 case TYPEVAR -> components(((TypeVar) seltype).getUpperBound());
 825                 default -> List.of(types.erasure(seltype));
 826             };
 827         }
 828 
 829         /* In a set of patterns, search for a sub-set of binding patterns that
 830          * in combination exhaust their sealed supertype. If such a sub-set
 831          * is found, it is removed, and replaced with a binding pattern
 832          * for the sealed supertype.
 833          */
 834         private Set<PatternDescription> reduceBindingPatterns(Type selectorType, Set<PatternDescription> patterns) {
 835             Set<Symbol> existingBindings = patterns.stream()
 836                                                    .filter(pd -> pd instanceof BindingPattern)
 837                                                    .map(pd -> ((BindingPattern) pd).type.tsym)
 838                                                    .collect(Collectors.toSet());
 839 
 840             for (PatternDescription pdOne : patterns) {
 841                 if (pdOne instanceof BindingPattern bpOne) {
 842                     Set<PatternDescription> toAdd = new HashSet<>();
 843 
 844                     for (Type sup : types.directSupertypes(bpOne.type)) {
 845                         ClassSymbol clazz = (ClassSymbol) sup.tsym;
 846 
 847                         clazz.complete();
 848 
 849                         if (clazz.isSealed() && clazz.isAbstract() &&
 850                             //if a binding pattern for clazz already exists, no need to analyze it again:
 851                             !existingBindings.contains(clazz)) {
 852                             ListBuffer<PatternDescription> bindings = new ListBuffer<>();
 853                             //do not reduce to types unrelated to the selector type:
 854                             Type clazzErasure = types.erasure(clazz.type);
 855                             if (components(selectorType).stream()
 856                                                         .map(types::erasure)
 857                                                         .noneMatch(c -> types.isSubtype(clazzErasure, c))) {
 858                                 continue;
 859                             }
 860 
 861                             Set<Symbol> permitted = allPermittedSubTypes(clazz, csym -> {
 862                                 Type instantiated;
 863                                 if (csym.type.allparams().isEmpty()) {
 864                                     instantiated = csym.type;
 865                                 } else {
 866                                     instantiated = infer.instantiatePatternType(selectorType, csym);
 867                                 }
 868 
 869                                 return instantiated != null && types.isCastable(selectorType, instantiated);
 870                             });
 871 
 872                             for (PatternDescription pdOther : patterns) {
 873                                 if (pdOther instanceof BindingPattern bpOther) {
 874                                     Set<Symbol> currentPermittedSubTypes =
 875                                             allPermittedSubTypes((ClassSymbol) bpOther.type.tsym, s -> true);
 876 
 877                                     PERMITTED: for (Iterator<Symbol> it = permitted.iterator(); it.hasNext();) {
 878                                         Symbol perm = it.next();
 879 
 880                                         for (Symbol currentPermitted : currentPermittedSubTypes) {
 881                                             if (types.isSubtype(types.erasure(currentPermitted.type),
 882                                                                 types.erasure(perm.type))) {
 883                                                 it.remove();
 884                                                 continue PERMITTED;
 885                                             }
 886                                         }
 887                                         if (types.isSubtype(types.erasure(perm.type),
 888                                                             types.erasure(bpOther.type))) {
 889                                             it.remove();
 890                                         }
 891                                     }
 892                                 }
 893                             }
 894 
 895                             if (permitted.isEmpty()) {
 896                                 toAdd.add(new BindingPattern(clazz.type));
 897                             }
 898                         }
 899                     }
 900 
 901                     if (!toAdd.isEmpty()) {
 902                         Set<PatternDescription> newPatterns = new HashSet<>(patterns);
 903                         newPatterns.addAll(toAdd);
 904                         return newPatterns;
 905                     }
 906                 }
 907             }
 908             return patterns;
 909         }
 910 
 911         private Set<Symbol> allPermittedSubTypes(ClassSymbol root, Predicate<ClassSymbol> accept) {
 912             Set<Symbol> permitted = new HashSet<>();
 913             List<ClassSymbol> permittedSubtypesClosure = List.of(root);
 914 
 915             while (permittedSubtypesClosure.nonEmpty()) {
 916                 ClassSymbol current = permittedSubtypesClosure.head;
 917 
 918                 permittedSubtypesClosure = permittedSubtypesClosure.tail;
 919 
 920                 current.complete();
 921 
 922                 if (current.isSealed() && current.isAbstract()) {
 923                     for (Symbol sym : current.permitted) {
 924                         ClassSymbol csym = (ClassSymbol) sym;
 925 
 926                         if (accept.test(csym)) {
 927                             permittedSubtypesClosure = permittedSubtypesClosure.prepend(csym);
 928                             permitted.add(csym);
 929                         }
 930                     }
 931                 }
 932             }
 933 
 934             return permitted;
 935         }
 936 
 937         /* Among the set of patterns, find sub-set of patterns such:
 938          * $record($prefix$, $nested, $suffix$)
 939          * Where $record, $prefix$ and $suffix$ is the same for each pattern
 940          * in the set, and the patterns only differ in one "column" in
 941          * the $nested pattern.
 942          * Then, the set of $nested patterns is taken, and passed recursively
 943          * to reduceNestedPatterns and to reduceBindingPatterns, to
 944          * simplify the pattern. If that succeeds, the original found sub-set
 945          * of patterns is replaced with a new set of patterns of the form:
 946          * $record($prefix$, $resultOfReduction, $suffix$)
 947          */
 948         private Set<PatternDescription> reduceNestedPatterns(Set<PatternDescription> patterns) {
 949             /* implementation note:
 950              * finding a sub-set of patterns that only differ in a single
 951              * column is time-consuming task, so this method speeds it up by:
 952              * - group the patterns by their record class
 953              * - for each column (nested pattern) do:
 954              * -- group patterns by their hash
 955              * -- in each such by-hash group, find sub-sets that only differ in
 956              *    the chosen column, and then call reduceBindingPatterns and reduceNestedPatterns
 957              *    on patterns in the chosen column, as described above
 958              */
 959             var groupByRecordClass =
 960                     patterns.stream()
 961                             .filter(pd -> pd instanceof RecordPattern)
 962                             .map(pd -> (RecordPattern) pd)
 963                             .collect(groupingBy(pd -> (ClassSymbol) pd.recordType.tsym));
 964 
 965             for (var e : groupByRecordClass.entrySet()) {
 966                 int nestedPatternsCount = e.getKey().getRecordComponents().size();
 967                 Set<RecordPattern> current = new HashSet<>(e.getValue());
 968 
 969                 for (int mismatchingCandidate = 0;
 970                      mismatchingCandidate < nestedPatternsCount;
 971                      mismatchingCandidate++) {
 972                     int mismatchingCandidateFin = mismatchingCandidate;
 973                     var groupByHashes =
 974                             current
 975                              .stream()
 976                              //error recovery, ignore patterns with incorrect number of nested patterns:
 977                              .filter(pd -> pd.nested.length == nestedPatternsCount)
 978                              .collect(groupingBy(pd -> pd.hashCode(mismatchingCandidateFin)));
 979                     for (var candidates : groupByHashes.values()) {
 980                         var candidatesArr = candidates.toArray(RecordPattern[]::new);
 981 
 982                         for (int firstCandidate = 0;
 983                              firstCandidate < candidatesArr.length;
 984                              firstCandidate++) {
 985                             RecordPattern rpOne = candidatesArr[firstCandidate];
 986                             ListBuffer<RecordPattern> join = new ListBuffer<>();
 987 
 988                             join.append(rpOne);
 989 
 990                             NEXT_PATTERN: for (int nextCandidate = 0;
 991                                                nextCandidate < candidatesArr.length;
 992                                                nextCandidate++) {
 993                                 if (firstCandidate == nextCandidate) {
 994                                     continue;
 995                                 }
 996 
 997                                 RecordPattern rpOther = candidatesArr[nextCandidate];
 998                                 if (rpOne.recordType.tsym == rpOther.recordType.tsym) {
 999                                     for (int i = 0; i < rpOne.nested.length; i++) {
1000                                         if (i != mismatchingCandidate &&
1001                                             !rpOne.nested[i].equals(rpOther.nested[i])) {
1002                                             continue NEXT_PATTERN;
1003                                         }
1004                                     }
1005                                     join.append(rpOther);
1006                                 }
1007                             }
1008 
1009                             var nestedPatterns = join.stream().map(rp -> rp.nested[mismatchingCandidateFin]).collect(Collectors.toSet());
1010                             var updatedPatterns = reduceNestedPatterns(nestedPatterns);
1011 
1012                             updatedPatterns = reduceRecordPatterns(updatedPatterns);
1013                             updatedPatterns = removeCoveredRecordPatterns(updatedPatterns);
1014                             updatedPatterns = reduceBindingPatterns(rpOne.fullComponentTypes()[mismatchingCandidateFin], updatedPatterns);
1015 
1016                             if (!nestedPatterns.equals(updatedPatterns)) {
1017                                 current.removeAll(join);
1018 
1019                                 for (PatternDescription nested : updatedPatterns) {
1020                                     PatternDescription[] newNested =
1021                                             Arrays.copyOf(rpOne.nested, rpOne.nested.length);
1022                                     newNested[mismatchingCandidateFin] = nested;
1023                                     current.add(new RecordPattern(rpOne.recordType(),
1024                                                                     rpOne.fullComponentTypes(),
1025                                                                     newNested));
1026                                 }
1027                             }
1028                         }
1029                     }
1030                 }
1031 
1032                 if (!current.equals(new HashSet<>(e.getValue()))) {
1033                     Set<PatternDescription> result = new HashSet<>(patterns);
1034                     result.removeAll(e.getValue());
1035                     result.addAll(current);
1036                     return result;
1037                 }
1038             }
1039             return patterns;
1040         }
1041 
1042         /* In the set of patterns, find those for which, given:
1043          * $record($nested1, $nested2, ...)
1044          * all the $nestedX pattern cover the given record component,
1045          * and replace those with a simple binding pattern over $record.
1046          */
1047         private Set<PatternDescription> reduceRecordPatterns(Set<PatternDescription> patterns) {
1048             var newPatterns = new HashSet<PatternDescription>();
1049             boolean modified = false;
1050             for (PatternDescription pd : patterns) {
1051                 if (pd instanceof RecordPattern rpOne) {
1052                     PatternDescription reducedPattern = reduceRecordPattern(rpOne);
1053                     if (reducedPattern != rpOne) {
1054                         newPatterns.add(reducedPattern);
1055                         modified = true;
1056                         continue;
1057                     }
1058                 }
1059                 newPatterns.add(pd);
1060             }
1061             return modified ? newPatterns : patterns;
1062         }
1063 
1064         private PatternDescription reduceRecordPattern(PatternDescription pattern) {
1065             if (pattern instanceof RecordPattern rpOne) {
1066                 Type[] componentType = rpOne.fullComponentTypes();
1067                 //error recovery, ignore patterns with incorrect number of nested patterns:
1068                 if (componentType.length != rpOne.nested.length) {
1069                     return pattern;
1070                 }
1071                 PatternDescription[] reducedNestedPatterns = null;
1072                 boolean covered = true;
1073                 for (int i = 0; i < componentType.length; i++) {
1074                     PatternDescription newNested = reduceRecordPattern(rpOne.nested[i]);
1075                     if (newNested != rpOne.nested[i]) {
1076                         if (reducedNestedPatterns == null) {
1077                             reducedNestedPatterns = Arrays.copyOf(rpOne.nested, rpOne.nested.length);
1078                         }
1079                         reducedNestedPatterns[i] = newNested;
1080                     }
1081 
1082                     covered &= newNested instanceof BindingPattern bp &&
1083                                types.isSubtype(types.erasure(componentType[i]), types.erasure(bp.type));
1084                 }
1085                 if (covered) {
1086                     return new BindingPattern(rpOne.recordType);
1087                 } else if (reducedNestedPatterns != null) {
1088                     return new RecordPattern(rpOne.recordType, rpOne.fullComponentTypes(), reducedNestedPatterns);
1089                 }
1090             }
1091             return pattern;
1092         }
1093 
1094         private Set<PatternDescription> removeCoveredRecordPatterns(Set<PatternDescription> patterns) {
1095             Set<Symbol> existingBindings = patterns.stream()
1096                                                    .filter(pd -> pd instanceof BindingPattern)
1097                                                    .map(pd -> ((BindingPattern) pd).type.tsym)
1098                                                    .collect(Collectors.toSet());
1099             Set<PatternDescription> result = new HashSet<>(patterns);
1100 
1101             for (Iterator<PatternDescription> it = result.iterator(); it.hasNext();) {
1102                 PatternDescription pd = it.next();
1103                 if (pd instanceof RecordPattern rp && existingBindings.contains(rp.recordType.tsym)) {
1104                     it.remove();
1105                 }
1106             }
1107 
1108             return result;
1109         }
1110 
1111         public void visitTry(JCTry tree) {
1112             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1113             pendingExits = new ListBuffer<>();
1114             for (JCTree resource : tree.resources) {
1115                 if (resource instanceof JCVariableDecl variableDecl) {
1116                     visitVarDef(variableDecl);
1117                 } else if (resource instanceof JCExpression expression) {
1118                     scan(expression);
1119                 } else {
1120                     throw new AssertionError(tree);  // parser error
1121                 }
1122             }
1123 
1124             scanStat(tree.body);
1125             Liveness aliveEnd = alive;
1126 
1127             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1128                 alive = Liveness.ALIVE;
1129                 JCVariableDecl param = l.head.param;
1130                 scan(param);
1131                 scanStat(l.head.body);
1132                 aliveEnd = aliveEnd.or(alive);
1133             }
1134             if (tree.finalizer != null) {
1135                 ListBuffer<PendingExit> exits = pendingExits;
1136                 pendingExits = prevPendingExits;
1137                 alive = Liveness.ALIVE;
1138                 scanStat(tree.finalizer);
1139                 tree.finallyCanCompleteNormally = alive != Liveness.DEAD;
1140                 if (alive == Liveness.DEAD) {
1141                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
1142                         log.warning(Lint.LintCategory.FINALLY,
1143                                 TreeInfo.diagEndPos(tree.finalizer),
1144                                 Warnings.FinallyCannotComplete);
1145                     }
1146                 } else {
1147                     while (exits.nonEmpty()) {
1148                         pendingExits.append(exits.next());
1149                     }
1150                     alive = aliveEnd;
1151                 }
1152             } else {
1153                 alive = aliveEnd;
1154                 ListBuffer<PendingExit> exits = pendingExits;
1155                 pendingExits = prevPendingExits;
1156                 while (exits.nonEmpty()) pendingExits.append(exits.next());
1157             }
1158         }
1159 
1160         @Override
1161         public void visitIf(JCIf tree) {
1162             scan(tree.cond);
1163             scanStat(tree.thenpart);
1164             if (tree.elsepart != null) {
1165                 Liveness aliveAfterThen = alive;
1166                 alive = Liveness.ALIVE;
1167                 scanStat(tree.elsepart);
1168                 alive = alive.or(aliveAfterThen);
1169             } else {
1170                 alive = Liveness.ALIVE;
1171             }
1172         }
1173 
1174         public void visitBreak(JCBreak tree) {
1175             recordExit(new PendingExit(tree));
1176         }
1177 
1178         @Override
1179         public void visitYield(JCYield tree) {
1180             scan(tree.value);
1181             recordExit(new PendingExit(tree));
1182         }
1183 
1184         public void visitContinue(JCContinue tree) {
1185             recordExit(new PendingExit(tree));
1186         }
1187 
1188         public void visitReturn(JCReturn tree) {
1189             scan(tree.expr);
1190             recordExit(new PendingExit(tree));
1191         }
1192 
1193         public void visitThrow(JCThrow tree) {
1194             scan(tree.expr);
1195             markDead();
1196         }
1197 
1198         public void visitApply(JCMethodInvocation tree) {
1199             scan(tree.meth);
1200             scan(tree.args);
1201         }
1202 
1203         public void visitNewClass(JCNewClass tree) {
1204             scan(tree.encl);
1205             scan(tree.args);
1206             if (tree.def != null) {
1207                 scan(tree.def);
1208             }
1209         }
1210 
1211         @Override
1212         public void visitLambda(JCLambda tree) {
1213             if (tree.type != null &&
1214                     tree.type.isErroneous()) {
1215                 return;
1216             }
1217 
1218             ListBuffer<PendingExit> prevPending = pendingExits;
1219             Liveness prevAlive = alive;
1220             try {
1221                 pendingExits = new ListBuffer<>();
1222                 alive = Liveness.ALIVE;
1223                 scanStat(tree.body);
1224                 tree.canCompleteNormally = alive != Liveness.DEAD;
1225             }
1226             finally {
1227                 pendingExits = prevPending;
1228                 alive = prevAlive;
1229             }
1230         }
1231 
1232         public void visitModuleDef(JCModuleDecl tree) {
1233             // Do nothing for modules
1234         }
1235 
1236     /**************************************************************************
1237      * main method
1238      *************************************************************************/
1239 
1240         /** Perform definite assignment/unassignment analysis on a tree.
1241          */
1242         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
1243             analyzeTree(env, env.tree, make);
1244         }
1245         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
1246             try {
1247                 attrEnv = env;
1248                 Flow.this.make = make;
1249                 pendingExits = new ListBuffer<>();
1250                 alive = Liveness.ALIVE;
1251                 scan(tree);
1252             } finally {
1253                 pendingExits = null;
1254                 Flow.this.make = null;
1255             }
1256         }
1257     }
1258 
1259     /**
1260      * This pass implements the second step of the dataflow analysis, namely
1261      * the exception analysis. This is to ensure that every checked exception that is
1262      * thrown is declared or caught. The analyzer uses some info that has been set by
1263      * the liveliness analyzer.
1264      */
1265     class FlowAnalyzer extends BaseAnalyzer {
1266 
1267         /** A flag that indicates whether the last statement could
1268          *  complete normally.
1269          */
1270         HashMap<Symbol, List<Type>> preciseRethrowTypes;
1271 
1272         /** The current class being defined.
1273          */
1274         JCClassDecl classDef;
1275 
1276         /** The list of possibly thrown declarable exceptions.
1277          */
1278         List<Type> thrown;
1279 
1280         /** The list of exceptions that are either caught or declared to be
1281          *  thrown.
1282          */
1283         List<Type> caught;
1284 
1285         class ThrownPendingExit extends BaseAnalyzer.PendingExit {
1286 
1287             Type thrown;
1288 
1289             ThrownPendingExit(JCTree tree, Type thrown) {
1290                 super(tree);
1291                 this.thrown = thrown;
1292             }
1293         }
1294 
1295         @Override
1296         void markDead() {
1297             //do nothing
1298         }
1299 
1300         /*-------------------- Exceptions ----------------------*/
1301 
1302         /** Complain that pending exceptions are not caught.
1303          */
1304         void errorUncaught() {
1305             for (PendingExit exit = pendingExits.next();
1306                  exit != null;
1307                  exit = pendingExits.next()) {
1308                 if (exit instanceof ThrownPendingExit thrownExit) {
1309                     if (classDef != null &&
1310                         classDef.pos == exit.tree.pos) {
1311                         log.error(exit.tree.pos(),
1312                                   Errors.UnreportedExceptionDefaultConstructor(thrownExit.thrown));
1313                     } else if (exit.tree.hasTag(VARDEF) &&
1314                             ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
1315                         log.error(exit.tree.pos(),
1316                                   Errors.UnreportedExceptionImplicitClose(thrownExit.thrown,
1317                                                                           ((JCVariableDecl)exit.tree).sym.name));
1318                     } else {
1319                         log.error(exit.tree.pos(),
1320                                   Errors.UnreportedExceptionNeedToCatchOrThrow(thrownExit.thrown));
1321                     }
1322                 } else {
1323                     Assert.check(log.hasErrorOn(exit.tree.pos()));
1324                 }
1325             }
1326         }
1327 
1328         /** Record that exception is potentially thrown and check that it
1329          *  is caught.
1330          */
1331         void markThrown(JCTree tree, Type exc) {
1332             if (!chk.isUnchecked(tree.pos(), exc)) {
1333                 if (!chk.isHandled(exc, caught)) {
1334                     pendingExits.append(new ThrownPendingExit(tree, exc));
1335                 }
1336                 thrown = chk.incl(exc, thrown);
1337             }
1338         }
1339 
1340     /*************************************************************************
1341      * Visitor methods for statements and definitions
1342      *************************************************************************/
1343 
1344         /* ------------ Visitor methods for various sorts of trees -------------*/
1345 
1346         public void visitClassDef(JCClassDecl tree) {
1347             if (tree.sym == null) return;
1348 
1349             JCClassDecl classDefPrev = classDef;
1350             List<Type> thrownPrev = thrown;
1351             List<Type> caughtPrev = caught;
1352             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
1353             Lint lintPrev = lint;
1354             boolean anonymousClass = tree.name == names.empty;
1355             pendingExits = new ListBuffer<>();
1356             if (!anonymousClass) {
1357                 caught = List.nil();
1358             }
1359             classDef = tree;
1360             thrown = List.nil();
1361             lint = lint.augment(tree.sym);
1362 
1363             try {
1364                 // process all the static initializers
1365                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1366                     if (!l.head.hasTag(METHODDEF) &&
1367                         (TreeInfo.flags(l.head) & STATIC) != 0) {
1368                         scan(l.head);
1369                         errorUncaught();
1370                     }
1371                 }
1372 
1373                 // add intersection of all throws clauses of initial constructors
1374                 // to set of caught exceptions, unless class is anonymous.
1375                 if (!anonymousClass) {
1376                     boolean firstConstructor = true;
1377                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1378                         if (TreeInfo.isInitialConstructor(l.head)) {
1379                             List<Type> mthrown =
1380                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
1381                             if (firstConstructor) {
1382                                 caught = mthrown;
1383                                 firstConstructor = false;
1384                             } else {
1385                                 caught = chk.intersect(mthrown, caught);
1386                             }
1387                         }
1388                     }
1389                 }
1390 
1391                 // process all the instance initializers
1392                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1393                     if (!l.head.hasTag(METHODDEF) &&
1394                         (TreeInfo.flags(l.head) & STATIC) == 0) {
1395                         scan(l.head);
1396                         errorUncaught();
1397                     }
1398                 }
1399 
1400                 // in an anonymous class, add the set of thrown exceptions to
1401                 // the throws clause of the synthetic constructor and propagate
1402                 // outwards.
1403                 // Changing the throws clause on the fly is okay here because
1404                 // the anonymous constructor can't be invoked anywhere else,
1405                 // and its type hasn't been cached.
1406                 if (anonymousClass) {
1407                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1408                         if (TreeInfo.isConstructor(l.head)) {
1409                             JCMethodDecl mdef = (JCMethodDecl)l.head;
1410                             scan(mdef);
1411                             mdef.thrown = make.Types(thrown);
1412                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
1413                         }
1414                     }
1415                     thrownPrev = chk.union(thrown, thrownPrev);
1416                 }
1417 
1418                 // process all the methods
1419                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1420                     if (anonymousClass && TreeInfo.isConstructor(l.head))
1421                         continue; // there can never be an uncaught exception.
1422                     if (l.head.hasTag(METHODDEF)) {
1423                         scan(l.head);
1424                         errorUncaught();
1425                     }
1426                 }
1427 
1428                 thrown = thrownPrev;
1429             } finally {
1430                 pendingExits = pendingExitsPrev;
1431                 caught = caughtPrev;
1432                 classDef = classDefPrev;
1433                 lint = lintPrev;
1434             }
1435         }
1436 
1437         public void visitMethodDef(JCMethodDecl tree) {
1438             if (tree.body == null) return;
1439 
1440             List<Type> caughtPrev = caught;
1441             List<Type> mthrown = tree.sym.type.getThrownTypes();
1442             Lint lintPrev = lint;
1443 
1444             lint = lint.augment(tree.sym);
1445 
1446             Assert.check(pendingExits.isEmpty());
1447 
1448             try {
1449                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1450                     JCVariableDecl def = l.head;
1451                     scan(def);
1452                 }
1453                 if (TreeInfo.isInitialConstructor(tree))
1454                     caught = chk.union(caught, mthrown);
1455                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
1456                     caught = mthrown;
1457                 // else we are in an instance initializer block;
1458                 // leave caught unchanged.
1459 
1460                 scan(tree.body);
1461 
1462                 List<PendingExit> exits = pendingExits.toList();
1463                 pendingExits = new ListBuffer<>();
1464                 while (exits.nonEmpty()) {
1465                     PendingExit exit = exits.head;
1466                     exits = exits.tail;
1467                     if (!(exit instanceof ThrownPendingExit)) {
1468                         Assert.check(exit.tree.hasTag(RETURN) ||
1469                                          log.hasErrorOn(exit.tree.pos()));
1470                     } else {
1471                         // uncaught throws will be reported later
1472                         pendingExits.append(exit);
1473                     }
1474                 }
1475             } finally {
1476                 caught = caughtPrev;
1477                 lint = lintPrev;
1478             }
1479         }
1480 
1481         public void visitVarDef(JCVariableDecl tree) {
1482             if (tree.init != null) {
1483                 Lint lintPrev = lint;
1484                 lint = lint.augment(tree.sym);
1485                 try{
1486                     scan(tree.init);
1487                 } finally {
1488                     lint = lintPrev;
1489                 }
1490             }
1491         }
1492 
1493         public void visitBlock(JCBlock tree) {
1494             scan(tree.stats);
1495         }
1496 
1497         public void visitDoLoop(JCDoWhileLoop tree) {
1498             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1499             pendingExits = new ListBuffer<>();
1500             scan(tree.body);
1501             resolveContinues(tree);
1502             scan(tree.cond);
1503             resolveBreaks(tree, prevPendingExits);
1504         }
1505 
1506         public void visitWhileLoop(JCWhileLoop tree) {
1507             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1508             pendingExits = new ListBuffer<>();
1509             scan(tree.cond);
1510             scan(tree.body);
1511             resolveContinues(tree);
1512             resolveBreaks(tree, prevPendingExits);
1513         }
1514 
1515         public void visitForLoop(JCForLoop tree) {
1516             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1517             scan(tree.init);
1518             pendingExits = new ListBuffer<>();
1519             if (tree.cond != null) {
1520                 scan(tree.cond);
1521             }
1522             scan(tree.body);
1523             resolveContinues(tree);
1524             scan(tree.step);
1525             resolveBreaks(tree, prevPendingExits);
1526         }
1527 
1528         public void visitForeachLoop(JCEnhancedForLoop tree) {
1529             visitVarDef(tree.var);
1530             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1531             scan(tree.expr);
1532             pendingExits = new ListBuffer<>();
1533             scan(tree.body);
1534             resolveContinues(tree);
1535             resolveBreaks(tree, prevPendingExits);
1536         }
1537 
1538         public void visitLabelled(JCLabeledStatement tree) {
1539             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1540             pendingExits = new ListBuffer<>();
1541             scan(tree.body);
1542             resolveBreaks(tree, prevPendingExits);
1543         }
1544 
1545         public void visitSwitch(JCSwitch tree) {
1546             handleSwitch(tree, tree.selector, tree.cases);
1547         }
1548 
1549         @Override
1550         public void visitSwitchExpression(JCSwitchExpression tree) {
1551             handleSwitch(tree, tree.selector, tree.cases);
1552         }
1553 
1554         private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
1555             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1556             pendingExits = new ListBuffer<>();
1557             scan(selector);
1558             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
1559                 JCCase c = l.head;
1560                 scan(c.labels);
1561                 scan(c.stats);
1562             }
1563             if (tree.hasTag(SWITCH_EXPRESSION)) {
1564                 resolveYields(tree, prevPendingExits);
1565             } else {
1566                 resolveBreaks(tree, prevPendingExits);
1567             }
1568         }
1569 
1570         public void visitTry(JCTry tree) {
1571             List<Type> caughtPrev = caught;
1572             List<Type> thrownPrev = thrown;
1573             thrown = List.nil();
1574             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1575                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1576                         ((JCTypeUnion)l.head.param.vartype).alternatives :
1577                         List.of(l.head.param.vartype);
1578                 for (JCExpression ct : subClauses) {
1579                     caught = chk.incl(ct.type, caught);
1580                 }
1581             }
1582 
1583             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1584             pendingExits = new ListBuffer<>();
1585             for (JCTree resource : tree.resources) {
1586                 if (resource instanceof JCVariableDecl variableDecl) {
1587                     visitVarDef(variableDecl);
1588                 } else if (resource instanceof JCExpression expression) {
1589                     scan(expression);
1590                 } else {
1591                     throw new AssertionError(tree);  // parser error
1592                 }
1593             }
1594             for (JCTree resource : tree.resources) {
1595                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1596                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1597                     List.of(resource.type);
1598                 for (Type sup : closeableSupertypes) {
1599                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1600                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1601                                 attrEnv,
1602                                 types.skipTypeVars(sup, false),
1603                                 names.close,
1604                                 List.nil(),
1605                                 List.nil());
1606                         Type mt = types.memberType(resource.type, closeMethod);
1607                         if (closeMethod.kind == MTH) {
1608                             for (Type t : mt.getThrownTypes()) {
1609                                 markThrown(resource, t);
1610                             }
1611                         }
1612                     }
1613                 }
1614             }
1615             scan(tree.body);
1616             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1617             thrown = thrownPrev;
1618             caught = caughtPrev;
1619 
1620             List<Type> caughtInTry = List.nil();
1621             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1622                 JCVariableDecl param = l.head.param;
1623                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1624                         ((JCTypeUnion)l.head.param.vartype).alternatives :
1625                         List.of(l.head.param.vartype);
1626                 List<Type> ctypes = List.nil();
1627                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
1628                 for (JCExpression ct : subClauses) {
1629                     Type exc = ct.type;
1630                     if (exc != syms.unknownType) {
1631                         ctypes = ctypes.append(exc);
1632                         if (types.isSameType(exc, syms.objectType))
1633                             continue;
1634                         var pos = subClauses.size() > 1 ? ct.pos() : l.head.pos();
1635                         checkCaughtType(pos, exc, thrownInTry, caughtInTry);
1636                         caughtInTry = chk.incl(exc, caughtInTry);
1637                     }
1638                 }
1639                 scan(param);
1640                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
1641                 scan(l.head.body);
1642                 preciseRethrowTypes.remove(param.sym);
1643             }
1644             if (tree.finalizer != null) {
1645                 List<Type> savedThrown = thrown;
1646                 thrown = List.nil();
1647                 ListBuffer<PendingExit> exits = pendingExits;
1648                 pendingExits = prevPendingExits;
1649                 scan(tree.finalizer);
1650                 if (!tree.finallyCanCompleteNormally) {
1651                     // discard exits and exceptions from try and finally
1652                     thrown = chk.union(thrown, thrownPrev);
1653                 } else {
1654                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1655                     thrown = chk.union(thrown, savedThrown);
1656                     // FIX: this doesn't preserve source order of exits in catch
1657                     // versus finally!
1658                     while (exits.nonEmpty()) {
1659                         pendingExits.append(exits.next());
1660                     }
1661                 }
1662             } else {
1663                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1664                 ListBuffer<PendingExit> exits = pendingExits;
1665                 pendingExits = prevPendingExits;
1666                 while (exits.nonEmpty()) pendingExits.append(exits.next());
1667             }
1668         }
1669 
1670         @Override
1671         public void visitIf(JCIf tree) {
1672             scan(tree.cond);
1673             scan(tree.thenpart);
1674             if (tree.elsepart != null) {
1675                 scan(tree.elsepart);
1676             }
1677         }
1678 
1679         @Override
1680         public void visitStringTemplate(JCStringTemplate tree) {
1681             JCExpression processor = tree.processor;
1682 
1683             if (processor != null) {
1684                 scan(processor);
1685                 Type interfaceType = types.asSuper(processor.type, syms.processorType.tsym);
1686 
1687                 if (interfaceType != null) {
1688                     List<Type> typeArguments = interfaceType.getTypeArguments();
1689 
1690                     if (typeArguments.size() == 2) {
1691                         Type throwType = typeArguments.tail.head;
1692 
1693                         if (throwType != null) {
1694                             markThrown(tree, throwType);
1695                         }
1696                     }
1697                 }
1698             }
1699 
1700             scan(tree.expressions);
1701         }
1702 
1703         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
1704             if (chk.subset(exc, caughtInTry)) {
1705                 log.error(pos, Errors.ExceptAlreadyCaught(exc));
1706             } else if (!chk.isUnchecked(pos, exc) &&
1707                     !isExceptionOrThrowable(exc) &&
1708                     !chk.intersects(exc, thrownInTry)) {
1709                 log.error(pos, Errors.ExceptNeverThrownInTry(exc));
1710             } else {
1711                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
1712                 // 'catchableThrownTypes' cannot possibly be empty - if 'exc' was an
1713                 // unchecked exception, the result list would not be empty, as the augmented
1714                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
1715                 // exception, that would have been covered in the branch above
1716                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
1717                         !isExceptionOrThrowable(exc)) {
1718                     Warning key = catchableThrownTypes.length() == 1 ?
1719                             Warnings.UnreachableCatch(catchableThrownTypes) :
1720                             Warnings.UnreachableCatch1(catchableThrownTypes);
1721                     log.warning(pos, key);
1722                 }
1723             }
1724         }
1725         //where
1726             private boolean isExceptionOrThrowable(Type exc) {
1727                 return exc.tsym == syms.throwableType.tsym ||
1728                     exc.tsym == syms.exceptionType.tsym;
1729             }
1730 
1731         public void visitBreak(JCBreak tree) {
1732             recordExit(new PendingExit(tree));
1733         }
1734 
1735         public void visitYield(JCYield tree) {
1736             scan(tree.value);
1737             recordExit(new PendingExit(tree));
1738         }
1739 
1740         public void visitContinue(JCContinue tree) {
1741             recordExit(new PendingExit(tree));
1742         }
1743 
1744         public void visitReturn(JCReturn tree) {
1745             scan(tree.expr);
1746             recordExit(new PendingExit(tree));
1747         }
1748 
1749         public void visitThrow(JCThrow tree) {
1750             scan(tree.expr);
1751             Symbol sym = TreeInfo.symbol(tree.expr);
1752             if (sym != null &&
1753                 sym.kind == VAR &&
1754                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
1755                 preciseRethrowTypes.get(sym) != null) {
1756                 for (Type t : preciseRethrowTypes.get(sym)) {
1757                     markThrown(tree, t);
1758                 }
1759             }
1760             else {
1761                 markThrown(tree, tree.expr.type);
1762             }
1763             markDead();
1764         }
1765 
1766         public void visitApply(JCMethodInvocation tree) {
1767             scan(tree.meth);
1768             scan(tree.args);
1769             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1770                 markThrown(tree, l.head);
1771         }
1772 
1773         public void visitNewClass(JCNewClass tree) {
1774             scan(tree.encl);
1775             scan(tree.args);
1776            // scan(tree.def);
1777             for (List<Type> l = tree.constructorType.getThrownTypes();
1778                  l.nonEmpty();
1779                  l = l.tail) {
1780                 markThrown(tree, l.head);
1781             }
1782             List<Type> caughtPrev = caught;
1783             try {
1784                 // If the new class expression defines an anonymous class,
1785                 // analysis of the anonymous constructor may encounter thrown
1786                 // types which are unsubstituted type variables.
1787                 // However, since the constructor's actual thrown types have
1788                 // already been marked as thrown, it is safe to simply include
1789                 // each of the constructor's formal thrown types in the set of
1790                 // 'caught/declared to be thrown' types, for the duration of
1791                 // the class def analysis.
1792                 if (tree.def != null)
1793                     for (List<Type> l = tree.constructor.type.getThrownTypes();
1794                          l.nonEmpty();
1795                          l = l.tail) {
1796                         caught = chk.incl(l.head, caught);
1797                     }
1798                 scan(tree.def);
1799             }
1800             finally {
1801                 caught = caughtPrev;
1802             }
1803         }
1804 
1805         @Override
1806         public void visitLambda(JCLambda tree) {
1807             if (tree.type != null &&
1808                     tree.type.isErroneous()) {
1809                 return;
1810             }
1811             List<Type> prevCaught = caught;
1812             List<Type> prevThrown = thrown;
1813             ListBuffer<PendingExit> prevPending = pendingExits;
1814             try {
1815                 pendingExits = new ListBuffer<>();
1816                 caught = tree.getDescriptorType(types).getThrownTypes();
1817                 thrown = List.nil();
1818                 scan(tree.body);
1819                 List<PendingExit> exits = pendingExits.toList();
1820                 pendingExits = new ListBuffer<>();
1821                 while (exits.nonEmpty()) {
1822                     PendingExit exit = exits.head;
1823                     exits = exits.tail;
1824                     if (!(exit instanceof ThrownPendingExit)) {
1825                         Assert.check(exit.tree.hasTag(RETURN) ||
1826                                         log.hasErrorOn(exit.tree.pos()));
1827                     } else {
1828                         // uncaught throws will be reported later
1829                         pendingExits.append(exit);
1830                     }
1831                 }
1832 
1833                 errorUncaught();
1834             } finally {
1835                 pendingExits = prevPending;
1836                 caught = prevCaught;
1837                 thrown = prevThrown;
1838             }
1839         }
1840 
1841         public void visitModuleDef(JCModuleDecl tree) {
1842             // Do nothing for modules
1843         }
1844 
1845     /**************************************************************************
1846      * main method
1847      *************************************************************************/
1848 
1849         /** Perform definite assignment/unassignment analysis on a tree.
1850          */
1851         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
1852             analyzeTree(env, env.tree, make);
1853         }
1854         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
1855             try {
1856                 attrEnv = env;
1857                 Flow.this.make = make;
1858                 pendingExits = new ListBuffer<>();
1859                 preciseRethrowTypes = new HashMap<>();
1860                 this.thrown = this.caught = null;
1861                 this.classDef = null;
1862                 scan(tree);
1863             } finally {
1864                 pendingExits = null;
1865                 Flow.this.make = null;
1866                 this.thrown = this.caught = null;
1867                 this.classDef = null;
1868             }
1869         }
1870     }
1871 
1872     /**
1873      * Specialized pass that performs reachability analysis on a lambda
1874      */
1875     class LambdaAliveAnalyzer extends AliveAnalyzer {
1876 
1877         boolean inLambda;
1878 
1879         @Override
1880         public void visitReturn(JCReturn tree) {
1881             //ignore lambda return expression (which might not even be attributed)
1882             recordExit(new PendingExit(tree));
1883         }
1884 
1885         @Override
1886         public void visitLambda(JCLambda tree) {
1887             if (inLambda || tree.getBodyKind() == BodyKind.EXPRESSION) {
1888                 return;
1889             }
1890             inLambda = true;
1891             try {
1892                 super.visitLambda(tree);
1893             } finally {
1894                 inLambda = false;
1895             }
1896         }
1897 
1898         @Override
1899         public void visitClassDef(JCClassDecl tree) {
1900             //skip
1901         }
1902     }
1903 
1904     /**
1905      * Determine if alive after the given tree.
1906      */
1907     class SnippetAliveAnalyzer extends AliveAnalyzer {
1908         @Override
1909         public void visitClassDef(JCClassDecl tree) {
1910             //skip
1911         }
1912         @Override
1913         public void visitLambda(JCLambda tree) {
1914             //skip
1915         }
1916         public boolean isAlive() {
1917             return super.alive != Liveness.DEAD;
1918         }
1919     }
1920 
1921     class SnippetBreakToAnalyzer extends AliveAnalyzer {
1922         private final JCTree breakTo;
1923         private boolean breaksTo;
1924 
1925         public SnippetBreakToAnalyzer(JCTree breakTo) {
1926             this.breakTo = breakTo;
1927         }
1928 
1929         @Override
1930         public void visitBreak(JCBreak tree) {
1931             breaksTo |= breakTo == tree.target && super.alive == Liveness.ALIVE;
1932         }
1933 
1934         public boolean breaksTo() {
1935             return breaksTo;
1936         }
1937     }
1938 
1939     /**
1940      * Specialized pass that performs DA/DU on a lambda
1941      */
1942     class LambdaAssignAnalyzer extends AssignAnalyzer {
1943         WriteableScope enclosedSymbols;
1944         boolean inLambda;
1945 
1946         LambdaAssignAnalyzer(Env<AttrContext> env) {
1947             enclosedSymbols = WriteableScope.create(env.enclClass.sym);
1948         }
1949 
1950         @Override
1951         public void visitLambda(JCLambda tree) {
1952             if (inLambda) {
1953                 return;
1954             }
1955             inLambda = true;
1956             try {
1957                 super.visitLambda(tree);
1958             } finally {
1959                 inLambda = false;
1960             }
1961         }
1962 
1963         @Override
1964         public void visitVarDef(JCVariableDecl tree) {
1965             enclosedSymbols.enter(tree.sym);
1966             super.visitVarDef(tree);
1967         }
1968         @Override
1969         protected boolean trackable(VarSymbol sym) {
1970             return enclosedSymbols.includes(sym) &&
1971                    sym.owner.kind == MTH;
1972         }
1973 
1974         @Override
1975         public void visitClassDef(JCClassDecl tree) {
1976             //skip
1977         }
1978     }
1979 
1980     /**
1981      * Specialized pass that performs inference of thrown types for lambdas.
1982      */
1983     class LambdaFlowAnalyzer extends FlowAnalyzer {
1984         List<Type> inferredThrownTypes;
1985         boolean inLambda;
1986         @Override
1987         public void visitLambda(JCLambda tree) {
1988             if ((tree.type != null &&
1989                     tree.type.isErroneous()) || inLambda) {
1990                 return;
1991             }
1992             List<Type> prevCaught = caught;
1993             List<Type> prevThrown = thrown;
1994             ListBuffer<PendingExit> prevPending = pendingExits;
1995             inLambda = true;
1996             try {
1997                 pendingExits = new ListBuffer<>();
1998                 caught = List.of(syms.throwableType);
1999                 thrown = List.nil();
2000                 scan(tree.body);
2001                 inferredThrownTypes = thrown;
2002             } finally {
2003                 pendingExits = prevPending;
2004                 caught = prevCaught;
2005                 thrown = prevThrown;
2006                 inLambda = false;
2007             }
2008         }
2009         @Override
2010         public void visitClassDef(JCClassDecl tree) {
2011             //skip
2012         }
2013     }
2014 
2015     /**
2016      * This pass implements (i) definite assignment analysis, which ensures that
2017      * each variable is assigned when used and (ii) definite unassignment analysis,
2018      * which ensures that no final variable is assigned more than once. This visitor
2019      * depends on the results of the liveliness analyzer. This pass is also used to mark
2020      * effectively-final local variables/parameters.
2021      */
2022 
2023     public class AssignAnalyzer extends BaseAnalyzer {
2024 
2025         /** The set of definitely assigned variables.
2026          */
2027         final Bits inits;
2028 
2029         /** The set of definitely unassigned variables.
2030          */
2031         final Bits uninits;
2032 
2033         /** The set of variables that are definitely unassigned everywhere
2034          *  in current try block. This variable is maintained lazily; it is
2035          *  updated only when something gets removed from uninits,
2036          *  typically by being assigned in reachable code.  To obtain the
2037          *  correct set of variables which are definitely unassigned
2038          *  anywhere in current try block, intersect uninitsTry and
2039          *  uninits.
2040          */
2041         final Bits uninitsTry;
2042 
2043         /** When analyzing a condition, inits and uninits are null.
2044          *  Instead we have:
2045          */
2046         final Bits initsWhenTrue;
2047         final Bits initsWhenFalse;
2048         final Bits uninitsWhenTrue;
2049         final Bits uninitsWhenFalse;
2050 
2051         /** A mapping from addresses to variable symbols.
2052          */
2053         protected JCVariableDecl[] vardecls;
2054 
2055         /** The current class being defined.
2056          */
2057         JCClassDecl classDef;
2058 
2059         /** The first variable sequence number in this class definition.
2060          */
2061         int firstadr;
2062 
2063         /** The next available variable sequence number.
2064          */
2065         protected int nextadr;
2066 
2067         /** The first variable sequence number in a block that can return.
2068          */
2069         protected int returnadr;
2070 
2071         /** The list of unreferenced automatic resources.
2072          */
2073         WriteableScope unrefdResources;
2074 
2075         /** Modified when processing a loop body the second time for DU analysis. */
2076         FlowKind flowKind = FlowKind.NORMAL;
2077 
2078         /** The starting position of the analyzed tree */
2079         int startPos;
2080 
2081         public class AssignPendingExit extends BaseAnalyzer.PendingExit {
2082 
2083             final Bits inits;
2084             final Bits uninits;
2085             final Bits exit_inits = new Bits(true);
2086             final Bits exit_uninits = new Bits(true);
2087 
2088             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2089                 super(tree);
2090                 this.inits = inits;
2091                 this.uninits = uninits;
2092                 this.exit_inits.assign(inits);
2093                 this.exit_uninits.assign(uninits);
2094             }
2095 
2096             @Override
2097             public void resolveJump() {
2098                 inits.andSet(exit_inits);
2099                 uninits.andSet(exit_uninits);
2100             }
2101         }
2102 
2103         public AssignAnalyzer() {
2104             this.inits = new Bits();
2105             uninits = new Bits();
2106             uninitsTry = new Bits();
2107             initsWhenTrue = new Bits(true);
2108             initsWhenFalse = new Bits(true);
2109             uninitsWhenTrue = new Bits(true);
2110             uninitsWhenFalse = new Bits(true);
2111         }
2112 
2113         private boolean isInitialConstructor = false;
2114 
2115         @Override
2116         protected void markDead() {
2117             if (!isInitialConstructor) {
2118                 inits.inclRange(returnadr, nextadr);
2119             } else {
2120                 for (int address = returnadr; address < nextadr; address++) {
2121                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2122                         inits.incl(address);
2123                     }
2124                 }
2125             }
2126             uninits.inclRange(returnadr, nextadr);
2127         }
2128 
2129         /*-------------- Processing variables ----------------------*/
2130 
2131         /** Do we need to track init/uninit state of this symbol?
2132          *  I.e. is symbol either a local or a blank final variable?
2133          */
2134         protected boolean trackable(VarSymbol sym) {
2135             return
2136                 sym.pos >= startPos &&
2137                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2138                 isFinalUninitializedField(sym)));
2139         }
2140 
2141         boolean isFinalUninitializedField(VarSymbol sym) {
2142             return sym.owner.kind == TYP &&
2143                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
2144                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2145         }
2146 
2147         boolean isFinalUninitializedStaticField(VarSymbol sym) {
2148             return isFinalUninitializedField(sym) && sym.isStatic();
2149         }
2150 
2151         /** Initialize new trackable variable by setting its address field
2152          *  to the next available sequence number and entering it under that
2153          *  index into the vars array.
2154          */
2155         void newVar(JCVariableDecl varDecl) {
2156             VarSymbol sym = varDecl.sym;
2157             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2158             if ((sym.flags() & FINAL) == 0) {
2159                 sym.flags_field |= EFFECTIVELY_FINAL;
2160             }
2161             sym.adr = nextadr;
2162             vardecls[nextadr] = varDecl;
2163             inits.excl(nextadr);
2164             uninits.incl(nextadr);
2165             nextadr++;
2166         }
2167 
2168         /** Record an initialization of a trackable variable.
2169          */
2170         void letInit(DiagnosticPosition pos, VarSymbol sym) {
2171             if (sym.adr >= firstadr && trackable(sym)) {
2172                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
2173                     if (!uninits.isMember(sym.adr)) {
2174                         //assignment targeting an effectively final variable
2175                         //makes the variable lose its status of effectively final
2176                         //if the variable is _not_ definitively unassigned
2177                         sym.flags_field &= ~EFFECTIVELY_FINAL;
2178                     } else {
2179                         uninit(sym);
2180                     }
2181                 }
2182                 else if ((sym.flags() & FINAL) != 0) {
2183                     if ((sym.flags() & PARAMETER) != 0) {
2184                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
2185                             log.error(pos, Errors.MulticatchParameterMayNotBeAssigned(sym));
2186                         }
2187                         else {
2188                             log.error(pos,
2189                                       Errors.FinalParameterMayNotBeAssigned(sym));
2190                         }
2191                     } else if (!uninits.isMember(sym.adr)) {
2192                         log.error(pos, diags.errorKey(flowKind.errKey, sym));
2193                     } else {
2194                         uninit(sym);
2195                     }
2196                 }
2197                 inits.incl(sym.adr);
2198             } else if ((sym.flags() & FINAL) != 0) {
2199                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2200             }
2201         }
2202         //where
2203             void uninit(VarSymbol sym) {
2204                 if (!inits.isMember(sym.adr)) {
2205                     // reachable assignment
2206                     uninits.excl(sym.adr);
2207                     uninitsTry.excl(sym.adr);
2208                 } else {
2209                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2210                     uninits.excl(sym.adr);
2211                 }
2212             }
2213 
2214         /** If tree is either a simple name or of the form this.name or
2215          *  C.this.name, and tree represents a trackable variable,
2216          *  record an initialization of the variable.
2217          */
2218         void letInit(JCTree tree) {
2219             tree = TreeInfo.skipParens(tree);
2220             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2221                 Symbol sym = TreeInfo.symbol(tree);
2222                 if (sym.kind == VAR) {
2223                     letInit(tree.pos(), (VarSymbol)sym);
2224                 }
2225             }
2226         }
2227 
2228         /** Check that trackable variable is initialized.
2229          */
2230         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2231             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2232         }
2233 
2234         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2235             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2236                 trackable(sym) &&
2237                 !inits.isMember(sym.adr) &&
2238                 (sym.flags_field & CLASH) == 0) {
2239                     log.error(pos, errkey);
2240                 inits.incl(sym.adr);
2241             }
2242         }
2243 
2244         /** Utility method to reset several Bits instances.
2245          */
2246         private void resetBits(Bits... bits) {
2247             for (Bits b : bits) {
2248                 b.reset();
2249             }
2250         }
2251 
2252         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2253          */
2254         void split(boolean setToNull) {
2255             initsWhenFalse.assign(inits);
2256             uninitsWhenFalse.assign(uninits);
2257             initsWhenTrue.assign(inits);
2258             uninitsWhenTrue.assign(uninits);
2259             if (setToNull) {
2260                 resetBits(inits, uninits);
2261             }
2262         }
2263 
2264         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
2265          */
2266         protected void merge() {
2267             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
2268             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
2269         }
2270 
2271     /* ************************************************************************
2272      * Visitor methods for statements and definitions
2273      *************************************************************************/
2274 
2275         /** Analyze an expression. Make sure to set (un)inits rather than
2276          *  (un)initsWhenTrue(WhenFalse) on exit.
2277          */
2278         void scanExpr(JCTree tree) {
2279             if (tree != null) {
2280                 scan(tree);
2281                 if (inits.isReset()) {
2282                     merge();
2283                 }
2284             }
2285         }
2286 
2287         /** Analyze a list of expressions.
2288          */
2289         void scanExprs(List<? extends JCExpression> trees) {
2290             if (trees != null)
2291                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
2292                     scanExpr(l.head);
2293         }
2294 
2295         void scanPattern(JCTree tree) {
2296             scan(tree);
2297         }
2298 
2299         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
2300          *  rather than (un)inits on exit.
2301          */
2302         void scanCond(JCTree tree) {
2303             if (tree.type.isFalse()) {
2304                 if (inits.isReset()) merge();
2305                 initsWhenTrue.assign(inits);
2306                 initsWhenTrue.inclRange(firstadr, nextadr);
2307                 uninitsWhenTrue.assign(uninits);
2308                 uninitsWhenTrue.inclRange(firstadr, nextadr);
2309                 initsWhenFalse.assign(inits);
2310                 uninitsWhenFalse.assign(uninits);
2311             } else if (tree.type.isTrue()) {
2312                 if (inits.isReset()) merge();
2313                 initsWhenFalse.assign(inits);
2314                 initsWhenFalse.inclRange(firstadr, nextadr);
2315                 uninitsWhenFalse.assign(uninits);
2316                 uninitsWhenFalse.inclRange(firstadr, nextadr);
2317                 initsWhenTrue.assign(inits);
2318                 uninitsWhenTrue.assign(uninits);
2319             } else {
2320                 scan(tree);
2321                 if (!inits.isReset())
2322                     split(tree.type != syms.unknownType);
2323             }
2324             if (tree.type != syms.unknownType) {
2325                 resetBits(inits, uninits);
2326             }
2327         }
2328 
2329         /* ------------ Visitor methods for various sorts of trees -------------*/
2330 
2331         public void visitClassDef(JCClassDecl tree) {
2332             if (tree.sym == null) {
2333                 return;
2334             }
2335 
2336             Lint lintPrev = lint;
2337             lint = lint.augment(tree.sym);
2338             try {
2339                 JCClassDecl classDefPrev = classDef;
2340                 int firstadrPrev = firstadr;
2341                 int nextadrPrev = nextadr;
2342                 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
2343 
2344                 pendingExits = new ListBuffer<>();
2345                 if (tree.name != names.empty) {
2346                     firstadr = nextadr;
2347                 }
2348                 classDef = tree;
2349                 try {
2350                     // define all the static fields
2351                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2352                         if (l.head.hasTag(VARDEF)) {
2353                             JCVariableDecl def = (JCVariableDecl)l.head;
2354                             if ((def.mods.flags & STATIC) != 0) {
2355                                 VarSymbol sym = def.sym;
2356                                 if (trackable(sym)) {
2357                                     newVar(def);
2358                                 }
2359                             }
2360                         }
2361                     }
2362 
2363                     // process all the static initializers
2364                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2365                         if (!l.head.hasTag(METHODDEF) &&
2366                             (TreeInfo.flags(l.head) & STATIC) != 0) {
2367                             scan(l.head);
2368                             clearPendingExits(false);
2369                         }
2370                     }
2371 
2372                     // verify all static final fields got initailized
2373                     for (int i = firstadr; i < nextadr; i++) {
2374                         JCVariableDecl vardecl = vardecls[i];
2375                         VarSymbol var = vardecl.sym;
2376                         if (var.owner == classDef.sym && var.isStatic()) {
2377                             checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2378                         }
2379                     }
2380 
2381                     // define all the instance fields
2382                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2383                         if (l.head.hasTag(VARDEF)) {
2384                             JCVariableDecl def = (JCVariableDecl)l.head;
2385                             if ((def.mods.flags & STATIC) == 0) {
2386                                 VarSymbol sym = def.sym;
2387                                 if (trackable(sym)) {
2388                                     newVar(def);
2389                                 }
2390                             }
2391                         }
2392                     }
2393 
2394                     // process all the instance initializers
2395                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2396                         if (!l.head.hasTag(METHODDEF) &&
2397                             (TreeInfo.flags(l.head) & STATIC) == 0) {
2398                             scan(l.head);
2399                             clearPendingExits(false);
2400                         }
2401                     }
2402 
2403                     // process all the methods
2404                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2405                         if (l.head.hasTag(METHODDEF)) {
2406                             scan(l.head);
2407                         }
2408                     }
2409                 } finally {
2410                     pendingExits = pendingExitsPrev;
2411                     nextadr = nextadrPrev;
2412                     firstadr = firstadrPrev;
2413                     classDef = classDefPrev;
2414                 }
2415             } finally {
2416                 lint = lintPrev;
2417             }
2418         }
2419 
2420         public void visitMethodDef(JCMethodDecl tree) {
2421             if (tree.body == null) {
2422                 return;
2423             }
2424 
2425             /*  MemberEnter can generate synthetic methods ignore them
2426              */
2427             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2428                 return;
2429             }
2430 
2431             Lint lintPrev = lint;
2432             lint = lint.augment(tree.sym);
2433             try {
2434                 final Bits initsPrev = new Bits(inits);
2435                 final Bits uninitsPrev = new Bits(uninits);
2436                 int nextadrPrev = nextadr;
2437                 int firstadrPrev = firstadr;
2438                 int returnadrPrev = returnadr;
2439 
2440                 Assert.check(pendingExits.isEmpty());
2441                 boolean lastInitialConstructor = isInitialConstructor;
2442                 try {
2443                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2444 
2445                     if (!isInitialConstructor) {
2446                         firstadr = nextadr;
2447                     }
2448                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2449                         JCVariableDecl def = l.head;
2450                         scan(def);
2451                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2452                         /*  If we are executing the code from Gen, then there can be
2453                          *  synthetic or mandated variables, ignore them.
2454                          */
2455                         initParam(def);
2456                     }
2457                     // else we are in an instance initializer block;
2458                     // leave caught unchanged.
2459                     scan(tree.body);
2460 
2461                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2462                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2463                     if (isInitialConstructor) {
2464                         boolean isSynthesized = (tree.sym.flags() &
2465                                                  GENERATEDCONSTR) != 0;
2466                         for (int i = firstadr; i < nextadr; i++) {
2467                             JCVariableDecl vardecl = vardecls[i];
2468                             VarSymbol var = vardecl.sym;
2469                             if (var.owner == classDef.sym && !var.isStatic()) {
2470                                 // choose the diagnostic position based on whether
2471                                 // the ctor is default(synthesized) or not
2472                                 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2473                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2474                                             var, Errors.VarNotInitializedInDefaultConstructor(var));
2475                                 } else if (isCompactOrGeneratedRecordConstructor) {
2476                                     boolean isInstanceRecordField = var.enclClass().isRecord() &&
2477                                             (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2478                                             var.owner.kind == TYP;
2479                                     if (isInstanceRecordField) {
2480                                         boolean notInitialized = !inits.isMember(var.adr);
2481                                         if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2482                                         /*  this way we indicate Lower that it should generate an initialization for this field
2483                                          *  in the compact constructor
2484                                          */
2485                                             var.flags_field |= UNINITIALIZED_FIELD;
2486                                         } else {
2487                                             checkInit(TreeInfo.diagEndPos(tree.body), var);
2488                                         }
2489                                     } else {
2490                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2491                                     }
2492                                 } else {
2493                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2494                                 }
2495                             }
2496                         }
2497                     }
2498                     clearPendingExits(true);
2499                 } finally {
2500                     inits.assign(initsPrev);
2501                     uninits.assign(uninitsPrev);
2502                     nextadr = nextadrPrev;
2503                     firstadr = firstadrPrev;
2504                     returnadr = returnadrPrev;
2505                     isInitialConstructor = lastInitialConstructor;
2506                 }
2507             } finally {
2508                 lint = lintPrev;
2509             }
2510         }
2511 
2512         private void clearPendingExits(boolean inMethod) {
2513             List<PendingExit> exits = pendingExits.toList();
2514             pendingExits = new ListBuffer<>();
2515             while (exits.nonEmpty()) {
2516                 PendingExit exit = exits.head;
2517                 exits = exits.tail;
2518                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2519                                  log.hasErrorOn(exit.tree.pos()),
2520                              exit.tree);
2521                 if (inMethod && isInitialConstructor) {
2522                     Assert.check(exit instanceof AssignPendingExit);
2523                     inits.assign(((AssignPendingExit) exit).exit_inits);
2524                     for (int i = firstadr; i < nextadr; i++) {
2525                         checkInit(exit.tree.pos(), vardecls[i].sym);
2526                     }
2527                 }
2528             }
2529         }
2530         protected void initParam(JCVariableDecl def) {
2531             inits.incl(def.sym.adr);
2532             uninits.excl(def.sym.adr);
2533         }
2534 
2535         public void visitVarDef(JCVariableDecl tree) {
2536             Lint lintPrev = lint;
2537             lint = lint.augment(tree.sym);
2538             try{
2539                 boolean track = trackable(tree.sym);
2540                 if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) {
2541                     newVar(tree);
2542                 }
2543                 if (tree.init != null) {
2544                     scanExpr(tree.init);
2545                     if (track) {
2546                         letInit(tree.pos(), tree.sym);
2547                     }
2548                 }
2549             } finally {
2550                 lint = lintPrev;
2551             }
2552         }
2553 
2554         public void visitBlock(JCBlock tree) {
2555             int nextadrPrev = nextadr;
2556             scan(tree.stats);
2557             nextadr = nextadrPrev;
2558         }
2559 
2560         public void visitDoLoop(JCDoWhileLoop tree) {
2561             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2562             FlowKind prevFlowKind = flowKind;
2563             flowKind = FlowKind.NORMAL;
2564             final Bits initsSkip = new Bits(true);
2565             final Bits uninitsSkip = new Bits(true);
2566             pendingExits = new ListBuffer<>();
2567             int prevErrors = log.nerrors;
2568             do {
2569                 final Bits uninitsEntry = new Bits(uninits);
2570                 uninitsEntry.excludeFrom(nextadr);
2571                 scan(tree.body);
2572                 resolveContinues(tree);
2573                 scanCond(tree.cond);
2574                 if (!flowKind.isFinal()) {
2575                     initsSkip.assign(initsWhenFalse);
2576                     uninitsSkip.assign(uninitsWhenFalse);
2577                 }
2578                 if (log.nerrors !=  prevErrors ||
2579                     flowKind.isFinal() ||
2580                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
2581                     break;
2582                 inits.assign(initsWhenTrue);
2583                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
2584                 flowKind = FlowKind.SPECULATIVE_LOOP;
2585             } while (true);
2586             flowKind = prevFlowKind;
2587             inits.assign(initsSkip);
2588             uninits.assign(uninitsSkip);
2589             resolveBreaks(tree, prevPendingExits);
2590         }
2591 
2592         public void visitWhileLoop(JCWhileLoop tree) {
2593             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2594             FlowKind prevFlowKind = flowKind;
2595             flowKind = FlowKind.NORMAL;
2596             final Bits initsSkip = new Bits(true);
2597             final Bits uninitsSkip = new Bits(true);
2598             pendingExits = new ListBuffer<>();
2599             int prevErrors = log.nerrors;
2600             final Bits uninitsEntry = new Bits(uninits);
2601             uninitsEntry.excludeFrom(nextadr);
2602             do {
2603                 scanCond(tree.cond);
2604                 if (!flowKind.isFinal()) {
2605                     initsSkip.assign(initsWhenFalse) ;
2606                     uninitsSkip.assign(uninitsWhenFalse);
2607                 }
2608                 inits.assign(initsWhenTrue);
2609                 uninits.assign(uninitsWhenTrue);
2610                 scan(tree.body);
2611                 resolveContinues(tree);
2612                 if (log.nerrors != prevErrors ||
2613                     flowKind.isFinal() ||
2614                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
2615                     break;
2616                 }
2617                 uninits.assign(uninitsEntry.andSet(uninits));
2618                 flowKind = FlowKind.SPECULATIVE_LOOP;
2619             } while (true);
2620             flowKind = prevFlowKind;
2621             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
2622             //branch is not taken AND if it's DA/DU before any break statement
2623             inits.assign(initsSkip);
2624             uninits.assign(uninitsSkip);
2625             resolveBreaks(tree, prevPendingExits);
2626         }
2627 
2628         public void visitForLoop(JCForLoop tree) {
2629             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2630             FlowKind prevFlowKind = flowKind;
2631             flowKind = FlowKind.NORMAL;
2632             int nextadrPrev = nextadr;
2633             scan(tree.init);
2634             final Bits initsSkip = new Bits(true);
2635             final Bits uninitsSkip = new Bits(true);
2636             pendingExits = new ListBuffer<>();
2637             int prevErrors = log.nerrors;
2638             do {
2639                 final Bits uninitsEntry = new Bits(uninits);
2640                 uninitsEntry.excludeFrom(nextadr);
2641                 if (tree.cond != null) {
2642                     scanCond(tree.cond);
2643                     if (!flowKind.isFinal()) {
2644                         initsSkip.assign(initsWhenFalse);
2645                         uninitsSkip.assign(uninitsWhenFalse);
2646                     }
2647                     inits.assign(initsWhenTrue);
2648                     uninits.assign(uninitsWhenTrue);
2649                 } else if (!flowKind.isFinal()) {
2650                     initsSkip.assign(inits);
2651                     initsSkip.inclRange(firstadr, nextadr);
2652                     uninitsSkip.assign(uninits);
2653                     uninitsSkip.inclRange(firstadr, nextadr);
2654                 }
2655                 scan(tree.body);
2656                 resolveContinues(tree);
2657                 scan(tree.step);
2658                 if (log.nerrors != prevErrors ||
2659                     flowKind.isFinal() ||
2660                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2661                     break;
2662                 uninits.assign(uninitsEntry.andSet(uninits));
2663                 flowKind = FlowKind.SPECULATIVE_LOOP;
2664             } while (true);
2665             flowKind = prevFlowKind;
2666             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
2667             //branch is not taken AND if it's DA/DU before any break statement
2668             inits.assign(initsSkip);
2669             uninits.assign(uninitsSkip);
2670             resolveBreaks(tree, prevPendingExits);
2671             nextadr = nextadrPrev;
2672         }
2673 
2674         public void visitForeachLoop(JCEnhancedForLoop tree) {
2675             visitVarDef(tree.var);
2676 
2677             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2678             FlowKind prevFlowKind = flowKind;
2679             flowKind = FlowKind.NORMAL;
2680             int nextadrPrev = nextadr;
2681             scan(tree.expr);
2682             final Bits initsStart = new Bits(inits);
2683             final Bits uninitsStart = new Bits(uninits);
2684 
2685             letInit(tree.pos(), tree.var.sym);
2686             pendingExits = new ListBuffer<>();
2687             int prevErrors = log.nerrors;
2688             do {
2689                 final Bits uninitsEntry = new Bits(uninits);
2690                 uninitsEntry.excludeFrom(nextadr);
2691                 scan(tree.body);
2692                 resolveContinues(tree);
2693                 if (log.nerrors != prevErrors ||
2694                     flowKind.isFinal() ||
2695                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2696                     break;
2697                 uninits.assign(uninitsEntry.andSet(uninits));
2698                 flowKind = FlowKind.SPECULATIVE_LOOP;
2699             } while (true);
2700             flowKind = prevFlowKind;
2701             inits.assign(initsStart);
2702             uninits.assign(uninitsStart.andSet(uninits));
2703             resolveBreaks(tree, prevPendingExits);
2704             nextadr = nextadrPrev;
2705         }
2706 
2707         public void visitLabelled(JCLabeledStatement tree) {
2708             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2709             pendingExits = new ListBuffer<>();
2710             scan(tree.body);
2711             resolveBreaks(tree, prevPendingExits);
2712         }
2713 
2714         public void visitSwitch(JCSwitch tree) {
2715             handleSwitch(tree, tree.selector, tree.cases, tree.isExhaustive);
2716         }
2717 
2718         public void visitSwitchExpression(JCSwitchExpression tree) {
2719             handleSwitch(tree, tree.selector, tree.cases, tree.isExhaustive);
2720         }
2721 
2722         private void handleSwitch(JCTree tree, JCExpression selector,
2723                                   List<JCCase> cases, boolean isExhaustive) {
2724             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2725             pendingExits = new ListBuffer<>();
2726             int nextadrPrev = nextadr;
2727             scanExpr(selector);
2728             final Bits initsSwitch = new Bits(inits);
2729             final Bits uninitsSwitch = new Bits(uninits);
2730             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
2731                 inits.assign(initsSwitch);
2732                 uninits.assign(uninits.andSet(uninitsSwitch));
2733                 JCCase c = l.head;
2734                 for (JCCaseLabel pat : c.labels) {
2735                     scanPattern(pat);
2736                 }
2737                 scan(c.guard);
2738                 if (inits.isReset()) {
2739                     inits.assign(initsWhenTrue);
2740                     uninits.assign(uninitsWhenTrue);
2741                 }
2742                 scan(c.stats);
2743                 if (c.completesNormally && c.caseKind == JCCase.RULE) {
2744                     scanSyntheticBreak(make, tree);
2745                 }
2746                 addVars(c.stats, initsSwitch, uninitsSwitch);
2747                 // Warn about fall-through if lint switch fallthrough enabled.
2748             }
2749             if (!isExhaustive) {
2750                 if (tree.hasTag(SWITCH_EXPRESSION)) {
2751                     markDead();
2752                 } else if (tree.hasTag(SWITCH) && !TreeInfo.expectedExhaustive((JCSwitch) tree)) {
2753                     inits.assign(initsSwitch);
2754                     uninits.assign(uninits.andSet(uninitsSwitch));
2755                 }
2756             }
2757             if (tree.hasTag(SWITCH_EXPRESSION)) {
2758                 resolveYields(tree, prevPendingExits);
2759             } else {
2760                 resolveBreaks(tree, prevPendingExits);
2761             }
2762             nextadr = nextadrPrev;
2763         }
2764         // where
2765             /** Add any variables defined in stats to inits and uninits. */
2766             private void addVars(List<JCStatement> stats, final Bits inits,
2767                                         final Bits uninits) {
2768                 for (;stats.nonEmpty(); stats = stats.tail) {
2769                     JCTree stat = stats.head;
2770                     if (stat.hasTag(VARDEF)) {
2771                         int adr = ((JCVariableDecl) stat).sym.adr;
2772                         inits.excl(adr);
2773                         uninits.incl(adr);
2774                     }
2775                 }
2776             }
2777 
2778         public void visitTry(JCTry tree) {
2779             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
2780             final Bits uninitsTryPrev = new Bits(uninitsTry);
2781             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2782             pendingExits = new ListBuffer<>();
2783             final Bits initsTry = new Bits(inits);
2784             uninitsTry.assign(uninits);
2785             for (JCTree resource : tree.resources) {
2786                 if (resource instanceof JCVariableDecl variableDecl) {
2787                     visitVarDef(variableDecl);
2788                     unrefdResources.enter(variableDecl.sym);
2789                     resourceVarDecls.append(variableDecl);
2790                 } else if (resource instanceof JCExpression expression) {
2791                     scanExpr(expression);
2792                 } else {
2793                     throw new AssertionError(tree);  // parser error
2794                 }
2795             }
2796             scan(tree.body);
2797             uninitsTry.andSet(uninits);
2798             final Bits initsEnd = new Bits(inits);
2799             final Bits uninitsEnd = new Bits(uninits);
2800             int nextadrCatch = nextadr;
2801 
2802             if (!resourceVarDecls.isEmpty() &&
2803                     lint.isEnabled(Lint.LintCategory.TRY)) {
2804                 for (JCVariableDecl resVar : resourceVarDecls) {
2805                     if (unrefdResources.includes(resVar.sym) && !resVar.sym.isUnnamedVariable()) {
2806                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
2807                                     Warnings.TryResourceNotReferenced(resVar.sym));
2808                         unrefdResources.remove(resVar.sym);
2809                     }
2810                 }
2811             }
2812 
2813             /*  The analysis of each catch should be independent.
2814              *  Each one should have the same initial values of inits and
2815              *  uninits.
2816              */
2817             final Bits initsCatchPrev = new Bits(initsTry);
2818             final Bits uninitsCatchPrev = new Bits(uninitsTry);
2819 
2820             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
2821                 JCVariableDecl param = l.head.param;
2822                 inits.assign(initsCatchPrev);
2823                 uninits.assign(uninitsCatchPrev);
2824                 scan(param);
2825                 /* If this is a TWR and we are executing the code from Gen,
2826                  * then there can be synthetic variables, ignore them.
2827                  */
2828                 initParam(param);
2829                 scan(l.head.body);
2830                 initsEnd.andSet(inits);
2831                 uninitsEnd.andSet(uninits);
2832                 nextadr = nextadrCatch;
2833             }
2834             if (tree.finalizer != null) {
2835                 inits.assign(initsTry);
2836                 uninits.assign(uninitsTry);
2837                 ListBuffer<PendingExit> exits = pendingExits;
2838                 pendingExits = prevPendingExits;
2839                 scan(tree.finalizer);
2840                 if (!tree.finallyCanCompleteNormally) {
2841                     // discard exits and exceptions from try and finally
2842                 } else {
2843                     uninits.andSet(uninitsEnd);
2844                     // FIX: this doesn't preserve source order of exits in catch
2845                     // versus finally!
2846                     while (exits.nonEmpty()) {
2847                         PendingExit exit = exits.next();
2848                         if (exit instanceof AssignPendingExit assignPendingExit) {
2849                             assignPendingExit.exit_inits.orSet(inits);
2850                             assignPendingExit.exit_uninits.andSet(uninits);
2851                         }
2852                         pendingExits.append(exit);
2853                     }
2854                     inits.orSet(initsEnd);
2855                 }
2856             } else {
2857                 inits.assign(initsEnd);
2858                 uninits.assign(uninitsEnd);
2859                 ListBuffer<PendingExit> exits = pendingExits;
2860                 pendingExits = prevPendingExits;
2861                 while (exits.nonEmpty()) pendingExits.append(exits.next());
2862             }
2863             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
2864         }
2865 
2866         public void visitConditional(JCConditional tree) {
2867             scanCond(tree.cond);
2868             final Bits initsBeforeElse = new Bits(initsWhenFalse);
2869             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2870             inits.assign(initsWhenTrue);
2871             uninits.assign(uninitsWhenTrue);
2872             if (tree.truepart.type.hasTag(BOOLEAN) &&
2873                 tree.falsepart.type.hasTag(BOOLEAN)) {
2874                 // if b and c are boolean valued, then
2875                 // v is (un)assigned after a?b:c when true iff
2876                 //    v is (un)assigned after b when true and
2877                 //    v is (un)assigned after c when true
2878                 scanCond(tree.truepart);
2879                 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
2880                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
2881                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
2882                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
2883                 inits.assign(initsBeforeElse);
2884                 uninits.assign(uninitsBeforeElse);
2885                 scanCond(tree.falsepart);
2886                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
2887                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
2888                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
2889                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
2890             } else {
2891                 scanExpr(tree.truepart);
2892                 final Bits initsAfterThen = new Bits(inits);
2893                 final Bits uninitsAfterThen = new Bits(uninits);
2894                 inits.assign(initsBeforeElse);
2895                 uninits.assign(uninitsBeforeElse);
2896                 scanExpr(tree.falsepart);
2897                 inits.andSet(initsAfterThen);
2898                 uninits.andSet(uninitsAfterThen);
2899             }
2900         }
2901 
2902         public void visitIf(JCIf tree) {
2903             scanCond(tree.cond);
2904             final Bits initsBeforeElse = new Bits(initsWhenFalse);
2905             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2906             inits.assign(initsWhenTrue);
2907             uninits.assign(uninitsWhenTrue);
2908             scan(tree.thenpart);
2909             if (tree.elsepart != null) {
2910                 final Bits initsAfterThen = new Bits(inits);
2911                 final Bits uninitsAfterThen = new Bits(uninits);
2912                 inits.assign(initsBeforeElse);
2913                 uninits.assign(uninitsBeforeElse);
2914                 scan(tree.elsepart);
2915                 inits.andSet(initsAfterThen);
2916                 uninits.andSet(uninitsAfterThen);
2917             } else {
2918                 inits.andSet(initsBeforeElse);
2919                 uninits.andSet(uninitsBeforeElse);
2920             }
2921         }
2922 
2923         @Override
2924         public void visitBreak(JCBreak tree) {
2925             recordExit(new AssignPendingExit(tree, inits, uninits));
2926         }
2927 
2928         @Override
2929         public void visitYield(JCYield tree) {
2930             JCSwitchExpression expr = (JCSwitchExpression) tree.target;
2931             if (expr != null && expr.type.hasTag(BOOLEAN)) {
2932                 scanCond(tree.value);
2933                 Bits initsAfterBreakWhenTrue = new Bits(initsWhenTrue);
2934                 Bits initsAfterBreakWhenFalse = new Bits(initsWhenFalse);
2935                 Bits uninitsAfterBreakWhenTrue = new Bits(uninitsWhenTrue);
2936                 Bits uninitsAfterBreakWhenFalse = new Bits(uninitsWhenFalse);
2937                 PendingExit exit = new PendingExit(tree) {
2938                     @Override
2939                     void resolveJump() {
2940                         if (!inits.isReset()) {
2941                             split(true);
2942                         }
2943                         initsWhenTrue.andSet(initsAfterBreakWhenTrue);
2944                         initsWhenFalse.andSet(initsAfterBreakWhenFalse);
2945                         uninitsWhenTrue.andSet(uninitsAfterBreakWhenTrue);
2946                         uninitsWhenFalse.andSet(uninitsAfterBreakWhenFalse);
2947                     }
2948                 };
2949                 merge();
2950                 recordExit(exit);
2951                 return ;
2952             } else {
2953                 scanExpr(tree.value);
2954                 recordExit(new AssignPendingExit(tree, inits, uninits));
2955             }
2956         }
2957 
2958         @Override
2959         public void visitContinue(JCContinue tree) {
2960             recordExit(new AssignPendingExit(tree, inits, uninits));
2961         }
2962 
2963         @Override
2964         public void visitReturn(JCReturn tree) {
2965             scanExpr(tree.expr);
2966             recordExit(new AssignPendingExit(tree, inits, uninits));
2967         }
2968 
2969         public void visitThrow(JCThrow tree) {
2970             scanExpr(tree.expr);
2971             markDead();
2972         }
2973 
2974         public void visitApply(JCMethodInvocation tree) {
2975             scanExpr(tree.meth);
2976             scanExprs(tree.args);
2977         }
2978 
2979         public void visitNewClass(JCNewClass tree) {
2980             scanExpr(tree.encl);
2981             scanExprs(tree.args);
2982             scan(tree.def);
2983         }
2984 
2985         @Override
2986         public void visitLambda(JCLambda tree) {
2987             final Bits prevUninits = new Bits(uninits);
2988             final Bits prevUninitsTry = new Bits(uninitsTry);
2989             final Bits prevInits = new Bits(inits);
2990             int returnadrPrev = returnadr;
2991             int nextadrPrev = nextadr;
2992             ListBuffer<PendingExit> prevPending = pendingExits;
2993             try {
2994                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
2995                 // body. This is by design: a variable that was definitely unassigned before the
2996                 // lambda body may end up being assigned to later on, so we cannot conclude that
2997                 // the variable will be unassigned when the body is executed.
2998                 uninits.excludeFrom(firstadr);
2999                 returnadr = nextadr;
3000                 pendingExits = new ListBuffer<>();
3001                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3002                     JCVariableDecl def = l.head;
3003                     scan(def);
3004                     inits.incl(def.sym.adr);
3005                     uninits.excl(def.sym.adr);
3006                 }
3007                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
3008                     scanExpr(tree.body);
3009                 } else {
3010                     scan(tree.body);
3011                 }
3012             }
3013             finally {
3014                 returnadr = returnadrPrev;
3015                 uninits.assign(prevUninits);
3016                 uninitsTry.assign(prevUninitsTry);
3017                 inits.assign(prevInits);
3018                 pendingExits = prevPending;
3019                 nextadr = nextadrPrev;
3020             }
3021         }
3022 
3023         public void visitNewArray(JCNewArray tree) {
3024             scanExprs(tree.dims);
3025             scanExprs(tree.elems);
3026         }
3027 
3028         public void visitAssert(JCAssert tree) {
3029             final Bits initsExit = new Bits(inits);
3030             final Bits uninitsExit = new Bits(uninits);
3031             scanCond(tree.cond);
3032             uninitsExit.andSet(uninitsWhenTrue);
3033             if (tree.detail != null) {
3034                 inits.assign(initsWhenFalse);
3035                 uninits.assign(uninitsWhenFalse);
3036                 scanExpr(tree.detail);
3037             }
3038             inits.assign(initsExit);
3039             uninits.assign(uninitsExit);
3040         }
3041 
3042         public void visitAssign(JCAssign tree) {
3043             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3044                 scanExpr(tree.lhs);
3045             scanExpr(tree.rhs);
3046             letInit(tree.lhs);
3047         }
3048 
3049         // check fields accessed through this.<field> are definitely
3050         // assigned before reading their value
3051         public void visitSelect(JCFieldAccess tree) {
3052             super.visitSelect(tree);
3053             if (TreeInfo.isThisQualifier(tree.selected) &&
3054                 tree.sym.kind == VAR) {
3055                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3056             }
3057         }
3058 
3059         public void visitAssignop(JCAssignOp tree) {
3060             scanExpr(tree.lhs);
3061             scanExpr(tree.rhs);
3062             letInit(tree.lhs);
3063         }
3064 
3065         public void visitUnary(JCUnary tree) {
3066             switch (tree.getTag()) {
3067             case NOT:
3068                 scanCond(tree.arg);
3069                 final Bits t = new Bits(initsWhenFalse);
3070                 initsWhenFalse.assign(initsWhenTrue);
3071                 initsWhenTrue.assign(t);
3072                 t.assign(uninitsWhenFalse);
3073                 uninitsWhenFalse.assign(uninitsWhenTrue);
3074                 uninitsWhenTrue.assign(t);
3075                 break;
3076             case PREINC: case POSTINC:
3077             case PREDEC: case POSTDEC:
3078                 scanExpr(tree.arg);
3079                 letInit(tree.arg);
3080                 break;
3081             default:
3082                 scanExpr(tree.arg);
3083             }
3084         }
3085 
3086         public void visitBinary(JCBinary tree) {
3087             switch (tree.getTag()) {
3088             case AND:
3089                 scanCond(tree.lhs);
3090                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
3091                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
3092                 inits.assign(initsWhenTrue);
3093                 uninits.assign(uninitsWhenTrue);
3094                 scanCond(tree.rhs);
3095                 initsWhenFalse.andSet(initsWhenFalseLeft);
3096                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
3097                 break;
3098             case OR:
3099                 scanCond(tree.lhs);
3100                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3101                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3102                 inits.assign(initsWhenFalse);
3103                 uninits.assign(uninitsWhenFalse);
3104                 scanCond(tree.rhs);
3105                 initsWhenTrue.andSet(initsWhenTrueLeft);
3106                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3107                 break;
3108             default:
3109                 scanExpr(tree.lhs);
3110                 scanExpr(tree.rhs);
3111             }
3112         }
3113 
3114         public void visitIdent(JCIdent tree) {
3115             if (tree.sym.kind == VAR) {
3116                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3117                 referenced(tree.sym);
3118             }
3119         }
3120 
3121         @Override
3122         public void visitTypeTest(JCInstanceOf tree) {
3123             scanExpr(tree.expr);
3124             scan(tree.pattern);
3125         }
3126 
3127         @Override
3128         public void visitBindingPattern(JCBindingPattern tree) {
3129             scan(tree.var);
3130             initParam(tree.var);
3131         }
3132 
3133         void referenced(Symbol sym) {
3134             unrefdResources.remove(sym);
3135         }
3136 
3137         public void visitAnnotatedType(JCAnnotatedType tree) {
3138             // annotations don't get scanned
3139             tree.underlyingType.accept(this);
3140         }
3141 
3142         public void visitModuleDef(JCModuleDecl tree) {
3143             // Do nothing for modules
3144         }
3145 
3146     /**************************************************************************
3147      * main method
3148      *************************************************************************/
3149 
3150         /** Perform definite assignment/unassignment analysis on a tree.
3151          */
3152         public void analyzeTree(Env<?> env, TreeMaker make) {
3153             analyzeTree(env, env.tree, make);
3154          }
3155 
3156         public void analyzeTree(Env<?> env, JCTree tree, TreeMaker make) {
3157             try {
3158                 startPos = tree.pos().getStartPosition();
3159 
3160                 if (vardecls == null)
3161                     vardecls = new JCVariableDecl[32];
3162                 else
3163                     for (int i=0; i<vardecls.length; i++)
3164                         vardecls[i] = null;
3165                 firstadr = 0;
3166                 nextadr = 0;
3167                 Flow.this.make = make;
3168                 pendingExits = new ListBuffer<>();
3169                 this.classDef = null;
3170                 unrefdResources = WriteableScope.create(env.enclClass.sym);
3171                 scan(tree);
3172             } finally {
3173                 // note that recursive invocations of this method fail hard
3174                 startPos = -1;
3175                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
3176                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
3177                 if (vardecls != null) {
3178                     for (int i=0; i<vardecls.length; i++)
3179                         vardecls[i] = null;
3180                 }
3181                 firstadr = 0;
3182                 nextadr = 0;
3183                 Flow.this.make = null;
3184                 pendingExits = null;
3185                 this.classDef = null;
3186                 unrefdResources = null;
3187             }
3188         }
3189     }
3190 
3191     /**
3192      * This pass implements the last step of the dataflow analysis, namely
3193      * the effectively-final analysis check. This checks that every local variable
3194      * reference from a lambda body/local inner class is either final or effectively final.
3195      * Additional this also checks that every variable that is used as an operand to
3196      * try-with-resources is final or effectively final.
3197      * As effectively final variables are marked as such during DA/DU, this pass must run after
3198      * AssignAnalyzer.
3199      */
3200     class CaptureAnalyzer extends BaseAnalyzer {
3201 
3202         JCTree currentTree; //local class or lambda
3203         WriteableScope declaredInsideGuard;
3204 
3205         @Override
3206         void markDead() {
3207             //do nothing
3208         }
3209 
3210         @SuppressWarnings("fallthrough")
3211         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
3212             if (currentTree != null &&
3213                     sym.owner.kind == MTH &&
3214                     sym.pos < getCurrentTreeStartPosition()) {
3215                 switch (currentTree.getTag()) {
3216                     case CLASSDEF:
3217                     case CASE:
3218                     case LAMBDA:
3219                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
3220                            reportEffectivelyFinalError(pos, sym);
3221                         }
3222                 }
3223             }
3224         }
3225 
3226         int getCurrentTreeStartPosition() {
3227             return currentTree instanceof JCCase cse ? cse.guard.getStartPosition()
3228                                                      : currentTree.getStartPosition();
3229         }
3230 
3231         @SuppressWarnings("fallthrough")
3232         void letInit(JCTree tree) {
3233             tree = TreeInfo.skipParens(tree);
3234             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
3235                 Symbol sym = TreeInfo.symbol(tree);
3236                 if (currentTree != null) {
3237                     switch (currentTree.getTag()) {
3238                         case CLASSDEF, LAMBDA -> {
3239                             if (sym.kind == VAR &&
3240                                 sym.owner.kind == MTH &&
3241                                 ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
3242                                 reportEffectivelyFinalError(tree, sym);
3243                             }
3244                         }
3245                         case CASE -> {
3246                             if (!declaredInsideGuard.includes(sym)) {
3247                                 log.error(tree.pos(), Errors.CannotAssignNotDeclaredGuard(sym));
3248                             }
3249                         }
3250                     }
3251                 }
3252             }
3253         }
3254 
3255         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
3256             Fragment subKey = switch (currentTree.getTag()) {
3257                 case LAMBDA -> Fragments.Lambda;
3258                 case CASE -> Fragments.Guard;
3259                 case CLASSDEF -> Fragments.InnerCls;
3260                 default -> throw new AssertionError("Unexpected tree kind: " + currentTree.getTag());
3261             };
3262             log.error(pos, Errors.CantRefNonEffectivelyFinalVar(sym, diags.fragment(subKey)));
3263         }
3264 
3265     /*************************************************************************
3266      * Visitor methods for statements and definitions
3267      *************************************************************************/
3268 
3269         /* ------------ Visitor methods for various sorts of trees -------------*/
3270 
3271         public void visitClassDef(JCClassDecl tree) {
3272             JCTree prevTree = currentTree;
3273             try {
3274                 currentTree = tree.sym.isDirectlyOrIndirectlyLocal() ? tree : null;
3275                 super.visitClassDef(tree);
3276             } finally {
3277                 currentTree = prevTree;
3278             }
3279         }
3280 
3281         @Override
3282         public void visitLambda(JCLambda tree) {
3283             JCTree prevTree = currentTree;
3284             try {
3285                 currentTree = tree;
3286                 super.visitLambda(tree);
3287             } finally {
3288                 currentTree = prevTree;
3289             }
3290         }
3291 
3292         @Override
3293         public void visitBindingPattern(JCBindingPattern tree) {
3294             scan(tree.var);
3295         }
3296 
3297         @Override
3298         public void visitCase(JCCase tree) {
3299             scan(tree.labels);
3300             if (tree.guard != null) {
3301                 JCTree prevTree = currentTree;
3302                 WriteableScope prevDeclaredInsideGuard = declaredInsideGuard;
3303                 try {
3304                     currentTree = tree;
3305                     declaredInsideGuard = WriteableScope.create(attrEnv.enclClass.sym);
3306                     scan(tree.guard);
3307                 } finally {
3308                     currentTree = prevTree;
3309                     declaredInsideGuard = prevDeclaredInsideGuard;
3310                 }
3311             }
3312             scan(tree.stats);
3313         }
3314 
3315         @Override
3316         public void visitRecordPattern(JCRecordPattern tree) {
3317             scan(tree.deconstructor);
3318             scan(tree.nested);
3319         }
3320 
3321         @Override
3322         public void visitIdent(JCIdent tree) {
3323             if (tree.sym.kind == VAR) {
3324                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
3325             }
3326         }
3327 
3328         public void visitAssign(JCAssign tree) {
3329             JCTree lhs = TreeInfo.skipParens(tree.lhs);
3330             if (!(lhs instanceof JCIdent)) {
3331                 scan(lhs);
3332             }
3333             scan(tree.rhs);
3334             letInit(lhs);
3335         }
3336 
3337         public void visitAssignop(JCAssignOp tree) {
3338             scan(tree.lhs);
3339             scan(tree.rhs);
3340             letInit(tree.lhs);
3341         }
3342 
3343         public void visitUnary(JCUnary tree) {
3344             switch (tree.getTag()) {
3345                 case PREINC: case POSTINC:
3346                 case PREDEC: case POSTDEC:
3347                     scan(tree.arg);
3348                     letInit(tree.arg);
3349                     break;
3350                 default:
3351                     scan(tree.arg);
3352             }
3353         }
3354 
3355         public void visitTry(JCTry tree) {
3356             for (JCTree resource : tree.resources) {
3357                 if (!resource.hasTag(VARDEF)) {
3358                     Symbol var = TreeInfo.symbol(resource);
3359                     if (var != null && (var.flags() & (FINAL | EFFECTIVELY_FINAL)) == 0) {
3360                         log.error(resource.pos(), Errors.TryWithResourcesExprEffectivelyFinalVar(var));
3361                     }
3362                 }
3363             }
3364             super.visitTry(tree);
3365         }
3366 
3367         @Override
3368         public void visitVarDef(JCVariableDecl tree) {
3369             if (declaredInsideGuard != null) {
3370                 declaredInsideGuard.enter(tree.sym);
3371             }
3372             super.visitVarDef(tree);
3373         }
3374 
3375         @Override
3376         public void visitYield(JCYield tree) {
3377             scan(tree.value);
3378         }
3379 
3380         public void visitModuleDef(JCModuleDecl tree) {
3381             // Do nothing for modules
3382         }
3383 
3384     /**************************************************************************
3385      * main method
3386      *************************************************************************/
3387 
3388         /** Perform definite assignment/unassignment analysis on a tree.
3389          */
3390         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
3391             analyzeTree(env, env.tree, make);
3392         }
3393         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
3394             try {
3395                 attrEnv = env;
3396                 Flow.this.make = make;
3397                 pendingExits = new ListBuffer<>();
3398                 scan(tree);
3399             } finally {
3400                 pendingExits = null;
3401                 Flow.this.make = null;
3402             }
3403         }
3404     }
3405 
3406     enum Liveness {
3407         ALIVE {
3408             @Override
3409             public Liveness or(Liveness other) {
3410                 return this;
3411             }
3412             @Override
3413             public Liveness and(Liveness other) {
3414                 return other;
3415             }
3416         },
3417         DEAD {
3418             @Override
3419             public Liveness or(Liveness other) {
3420                 return other;
3421             }
3422             @Override
3423             public Liveness and(Liveness other) {
3424                 return this;
3425             }
3426         },
3427         RECOVERY {
3428             @Override
3429             public Liveness or(Liveness other) {
3430                 if (other == ALIVE) {
3431                     return ALIVE;
3432                 } else {
3433                     return this;
3434                 }
3435             }
3436             @Override
3437             public Liveness and(Liveness other) {
3438                 if (other == DEAD) {
3439                     return DEAD;
3440                 } else {
3441                     return this;
3442                 }
3443             }
3444         };
3445 
3446         public abstract Liveness or(Liveness other);
3447         public abstract Liveness and(Liveness other);
3448         public Liveness or(boolean value) {
3449             return or(from(value));
3450         }
3451         public Liveness and(boolean value) {
3452             return and(from(value));
3453         }
3454         public static Liveness from(boolean value) {
3455             return value ? ALIVE : DEAD;
3456         }
3457     }
3458 
3459     sealed interface PatternDescription { }
3460     public PatternDescription makePatternDescription(Type selectorType, JCPattern pattern) {
3461         if (pattern instanceof JCBindingPattern binding) {
3462             Type type = types.isSubtype(selectorType, binding.type)
3463                     ? selectorType : binding.type;
3464             return new BindingPattern(type);
3465         } else if (pattern instanceof JCRecordPattern record) {
3466             Type[] componentTypes;
3467 
3468             if (!record.type.isErroneous()) {
3469                 componentTypes = ((ClassSymbol) record.type.tsym).getRecordComponents()
3470                         .map(r -> types.memberType(record.type, r))
3471                         .toArray(s -> new Type[s]);
3472             }
3473             else {
3474                 componentTypes = record.nested.map(t -> types.createErrorType(t.type)).toArray(s -> new Type[s]);;
3475             }
3476 
3477             PatternDescription[] nestedDescriptions =
3478                     new PatternDescription[record.nested.size()];
3479             int i = 0;
3480             for (List<JCPattern> it = record.nested;
3481                  it.nonEmpty();
3482                  it = it.tail, i++) {
3483                 Type componentType = i < componentTypes.length ? componentTypes[i]
3484                                                                : syms.errType;
3485                 nestedDescriptions[i] = makePatternDescription(types.erasure(componentType), it.head);
3486             }
3487             return new RecordPattern(record.type, componentTypes, nestedDescriptions);
3488         } else if (pattern instanceof JCAnyPattern) {
3489             return new BindingPattern(selectorType);
3490         } else {
3491             throw Assert.error();
3492         }
3493     }
3494     record BindingPattern(Type type) implements PatternDescription {
3495         @Override
3496         public int hashCode() {
3497             return type.tsym.hashCode();
3498         }
3499         @Override
3500         public boolean equals(Object o) {
3501             return o instanceof BindingPattern other &&
3502                     type.tsym == other.type.tsym;
3503         }
3504         @Override
3505         public String toString() {
3506             return type.tsym + " _";
3507         }
3508     }
3509     record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription... nested) implements PatternDescription {
3510 
3511         public RecordPattern(Type recordType, Type[] fullComponentTypes, PatternDescription[] nested) {
3512             this(recordType, hashCode(-1, recordType, nested), fullComponentTypes, nested);
3513         }
3514 
3515         @Override
3516         public int hashCode() {
3517             return _hashCode;
3518         }
3519 
3520         @Override
3521         public boolean equals(Object o) {
3522             return o instanceof RecordPattern other &&
3523                     recordType.tsym == other.recordType.tsym &&
3524                     Arrays.equals(nested, other.nested);
3525         }
3526 
3527         public int hashCode(int excludeComponent) {
3528             return hashCode(excludeComponent, recordType, nested);
3529         }
3530 
3531         public static int hashCode(int excludeComponent, Type recordType, PatternDescription... nested) {
3532             int hash = 5;
3533             hash =  41 * hash + recordType.tsym.hashCode();
3534             for (int  i = 0; i < nested.length; i++) {
3535                 if (i != excludeComponent) {
3536                     hash = 41 * hash + nested[i].hashCode();
3537                 }
3538             }
3539             return hash;
3540         }
3541         @Override
3542         public String toString() {
3543             return recordType.tsym + "(" + Arrays.stream(nested)
3544                     .map(pd -> pd.toString())
3545                     .collect(Collectors.joining(", ")) + ")";
3546         }
3547     }
3548 }