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