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