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