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