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