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