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