1 /*
   2  * Copyright (c) 2012, 2021, 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 package com.sun.tools.javac.comp;
  27 
  28 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
  29 import com.sun.source.tree.NewClassTree;
  30 import com.sun.tools.javac.code.*;
  31 import com.sun.tools.javac.code.Type.ErrorType;
  32 import com.sun.tools.javac.code.Type.MethodType;
  33 import com.sun.tools.javac.code.Type.StructuralTypeMapping;
  34 import com.sun.tools.javac.code.Types.TypeMapping;
  35 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
  36 import com.sun.tools.javac.comp.Infer.GraphSolver.InferenceGraph;
  37 import com.sun.tools.javac.comp.Resolve.ResolveError;
  38 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  39 import com.sun.tools.javac.tree.*;
  40 import com.sun.tools.javac.util.*;
  41 import com.sun.tools.javac.util.DefinedBy.Api;
  42 import com.sun.tools.javac.util.GraphUtils.DependencyKind;
  43 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  44 import com.sun.tools.javac.comp.Attr.ResultInfo;
  45 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
  46 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  47 import com.sun.tools.javac.tree.JCTree.*;
  48 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
  49 import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
  50 import com.sun.tools.javac.util.Log.DiagnosticHandler;
  51 
  52 import java.util.ArrayList;
  53 import java.util.Collection;
  54 import java.util.Collections;
  55 import java.util.EnumSet;
  56 import java.util.HashSet;
  57 import java.util.LinkedHashSet;
  58 import java.util.Map;
  59 import java.util.Set;
  60 import java.util.WeakHashMap;
  61 import java.util.function.Predicate;
  62 import java.util.function.Supplier;
  63 
  64 import com.sun.source.tree.MemberReferenceTree;
  65 import com.sun.tools.javac.code.Type;
  66 import com.sun.tools.javac.tree.JCTree.JCMemberReference.OverloadKind;
  67 
  68 import static com.sun.tools.javac.code.TypeTag.*;
  69 import com.sun.tools.javac.comp.Annotate.Queues;
  70 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  71 
  72 /**
  73  * This is an helper class that is used to perform deferred type-analysis.
  74  * Each time a poly expression occurs in argument position, javac attributes it
  75  * with a temporary 'deferred type' that is checked (possibly multiple times)
  76  * against an expected formal type.
  77  *
  78  *  <p><b>This is NOT part of any supported API.
  79  *  If you write code that depends on this, you do so at your own risk.
  80  *  This code and its internal interfaces are subject to change or
  81  *  deletion without notice.</b>
  82  */
  83 public class DeferredAttr extends JCTree.Visitor {
  84     protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
  85 
  86     final Annotate annotate;
  87     final Attr attr;
  88     final ArgumentAttr argumentAttr;
  89     final Check chk;
  90     final JCDiagnostic.Factory diags;
  91     final Enter enter;
  92     final Infer infer;
  93     final Resolve rs;
  94     final Log log;
  95     final Symtab syms;
  96     final TreeMaker make;
  97     final TreeCopier<Void> treeCopier;
  98     final TypeMapping<Void> deferredCopier;
  99     final Types types;
 100     final Flow flow;
 101     final Names names;
 102     final TypeEnvs typeEnvs;
 103     final DeferredCompletionFailureHandler dcfh;
 104 
 105     public static DeferredAttr instance(Context context) {
 106         DeferredAttr instance = context.get(deferredAttrKey);
 107         if (instance == null)
 108             instance = new DeferredAttr(context);
 109         return instance;
 110     }
 111 
 112     @SuppressWarnings("this-escape")
 113     protected DeferredAttr(Context context) {
 114         context.put(deferredAttrKey, this);
 115         annotate = Annotate.instance(context);
 116         attr = Attr.instance(context);
 117         argumentAttr = ArgumentAttr.instance(context);
 118         chk = Check.instance(context);
 119         diags = JCDiagnostic.Factory.instance(context);
 120         enter = Enter.instance(context);
 121         infer = Infer.instance(context);
 122         rs = Resolve.instance(context);
 123         log = Log.instance(context);
 124         syms = Symtab.instance(context);
 125         make = TreeMaker.instance(context);
 126         types = Types.instance(context);
 127         flow = Flow.instance(context);
 128         names = Names.instance(context);
 129         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
 130         typeEnvs = TypeEnvs.instance(context);
 131         dcfh = DeferredCompletionFailureHandler.instance(context);
 132         emptyDeferredAttrContext =
 133             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
 134                 @Override
 135                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
 136                     Assert.error("Empty deferred context!");
 137                 }
 138                 @Override
 139                 void complete() {
 140                     Assert.error("Empty deferred context!");
 141                 }
 142 
 143                 @Override
 144                 public String toString() {
 145                     return "Empty deferred context!";
 146                 }
 147             };
 148 
 149         // For speculative attribution, skip the class definition in <>.
 150         treeCopier =
 151             new TreeCopier<Void>(make) {
 152                 @Override @DefinedBy(Api.COMPILER_TREE)
 153                 public JCTree visitNewClass(NewClassTree node, Void p) {
 154                     JCNewClass t = (JCNewClass) node;
 155                     if (TreeInfo.isDiamond(t)) {
 156                         JCExpression encl = copy(t.encl, p);
 157                         List<JCExpression> typeargs = copy(t.typeargs, p);
 158                         JCExpression clazz = copy(t.clazz, p);
 159                         List<JCExpression> args = copy(t.args, p);
 160                         JCClassDecl def = null;
 161                         return make.at(t.pos).SpeculativeNewClass(encl, typeargs, clazz, args, def, t.def != null || t.classDeclRemoved());
 162                     } else {
 163                         return super.visitNewClass(node, p);
 164                     }
 165                 }
 166 
 167                 @Override @DefinedBy(Api.COMPILER_TREE)
 168                 public JCTree visitMemberReference(MemberReferenceTree node, Void p) {
 169                     JCMemberReference t = (JCMemberReference) node;
 170                     JCExpression expr = copy(t.expr, p);
 171                     List<JCExpression> typeargs = copy(t.typeargs, p);
 172                     /** once the value for overloadKind is determined for a copy, it can be safely forwarded to
 173                      *  the copied tree, we want to profit from that
 174                      */
 175                     JCMemberReference result = new JCMemberReference(t.mode, t.name, expr, typeargs) {
 176                         @Override
 177                         public void setOverloadKind(OverloadKind overloadKind) {
 178                             OverloadKind previous = t.getOverloadKind();
 179                             if (previous == null || previous == OverloadKind.ERROR) {
 180                                 t.setOverloadKind(overloadKind);
 181                             } else {
 182                                 Assert.check(previous == overloadKind || overloadKind == OverloadKind.ERROR);
 183                             }
 184                         }
 185 
 186                         @Override
 187                         public OverloadKind getOverloadKind() {
 188                             return t.getOverloadKind();
 189                         }
 190                     };
 191                     result.pos = t.pos;
 192                     return result;
 193                 }
 194             };
 195         deferredCopier = new TypeMapping<Void> () {
 196                 @Override
 197                 public Type visitType(Type t, Void v) {
 198                     if (t.hasTag(DEFERRED)) {
 199                         DeferredType dt = (DeferredType) t;
 200                         return new DeferredType(treeCopier.copy(dt.tree), dt.env);
 201                     }
 202                     return t;
 203                 }
 204             };
 205     }
 206 
 207     /** shared tree for stuck expressions */
 208     final JCTree stuckTree;
 209 
 210     /**
 211      * This type represents a deferred type. A deferred type starts off with
 212      * no information on the underlying expression type. Such info needs to be
 213      * discovered through type-checking the deferred type against a target-type.
 214      * Every deferred type keeps a pointer to the AST node from which it originated.
 215      */
 216     public class DeferredType extends Type {
 217 
 218         public JCExpression tree;
 219         Env<AttrContext> env;
 220         AttrMode mode;
 221         Set<Symbol> notPertinentToApplicability = new HashSet<>();
 222         SpeculativeCache speculativeCache;
 223 
 224         DeferredType(JCExpression tree, Env<AttrContext> env) {
 225             super(null, List.nil());
 226             this.tree = tree;
 227             this.env = attr.copyEnv(env);
 228             this.speculativeCache = new SpeculativeCache();
 229         }
 230 
 231         @Override
 232         public TypeTag getTag() {
 233             return DEFERRED;
 234         }
 235 
 236         @Override @DefinedBy(Api.LANGUAGE_MODEL)
 237         public String toString() {
 238             return "DeferredType";
 239         }
 240 
 241         /**
 242          * A speculative cache is used to keep track of all overload resolution rounds
 243          * that triggered speculative attribution on a given deferred type. Each entry
 244          * stores a pointer to the speculative tree and the resolution phase in which the entry
 245          * has been added.
 246          */
 247         class SpeculativeCache {
 248 
 249             private Map<Symbol, List<Entry>> cache = new WeakHashMap<>();
 250 
 251             class Entry {
 252                 JCTree speculativeTree;
 253                 ResultInfo resultInfo;
 254 
 255                 public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
 256                     this.speculativeTree = speculativeTree;
 257                     this.resultInfo = resultInfo;
 258                 }
 259 
 260                 boolean matches(MethodResolutionPhase phase) {
 261                     return resultInfo.checkContext.deferredAttrContext().phase == phase;
 262                 }
 263             }
 264 
 265             /**
 266              * Retrieve a speculative cache entry corresponding to given symbol
 267              * and resolution phase
 268              */
 269             Entry get(Symbol msym, MethodResolutionPhase phase) {
 270                 List<Entry> entries = cache.get(msym);
 271                 if (entries == null) return null;
 272                 for (Entry e : entries) {
 273                     if (e.matches(phase)) return e;
 274                 }
 275                 return null;
 276             }
 277 
 278             /**
 279              * Stores a speculative cache entry corresponding to given symbol
 280              * and resolution phase
 281              */
 282             void put(JCTree speculativeTree, ResultInfo resultInfo) {
 283                 Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
 284                 List<Entry> entries = cache.get(msym);
 285                 if (entries == null) {
 286                     entries = List.nil();
 287                 }
 288                 cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
 289             }
 290         }
 291 
 292         /**
 293          * Get the type that has been computed during a speculative attribution round
 294          */
 295         Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
 296             SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
 297             return e != null ? e.speculativeTree.type : Type.noType;
 298         }
 299 
 300         JCTree speculativeTree(DeferredAttrContext deferredAttrContext) {
 301             DeferredType.SpeculativeCache.Entry e = speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase);
 302             return e != null ? e.speculativeTree : stuckTree;
 303         }
 304 
 305         public Type complete(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 306             switch (deferredAttrContext.mode) {
 307                 case SPECULATIVE:
 308                     //Note: if a symbol is imported twice we might do two identical
 309                     //speculative rounds...
 310                     Assert.check(mode == null || mode == AttrMode.SPECULATIVE);
 311                     JCTree speculativeTree = attribSpeculative(tree, env, resultInfo);
 312                     speculativeCache.put(speculativeTree, resultInfo);
 313                     return speculativeTree.type;
 314                 case CHECK:
 315                     Assert.check(mode != null);
 316                     return attr.attribTree(tree, env, resultInfo);
 317             }
 318             Assert.error();
 319             return null;
 320         }
 321 
 322         /**
 323          * Check a deferred type against a potential target-type. Depending on
 324          * the current attribution mode, a normal vs. speculative attribution
 325          * round is performed on the underlying AST node. There can be only one
 326          * speculative round for a given target method symbol; moreover, a normal
 327          * attribution round must follow one or more speculative rounds.
 328          */
 329         Type check(ResultInfo resultInfo) {
 330             DeferredStuckPolicy deferredStuckPolicy;
 331             if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
 332                 deferredStuckPolicy = dummyStuckPolicy;
 333             } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE ||
 334                     resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()) {
 335                 deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
 336             } else {
 337                 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
 338             }
 339             return check(resultInfo, deferredStuckPolicy);
 340         }
 341 
 342         private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
 343             DeferredAttrContext deferredAttrContext =
 344                     resultInfo.checkContext.deferredAttrContext();
 345             Assert.check(deferredAttrContext != emptyDeferredAttrContext);
 346             if (deferredStuckPolicy.isStuck()) {
 347                 deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
 348                 if (deferredAttrContext.mode == AttrMode.SPECULATIVE) {
 349                     notPertinentToApplicability.add(deferredAttrContext.msym);
 350                     mode = AttrMode.SPECULATIVE;
 351                 }
 352                 return Type.noType;
 353             } else {
 354                 try {
 355                     return complete(resultInfo, deferredAttrContext);
 356                 } finally {
 357                     mode = deferredAttrContext.mode;
 358                 }
 359             }
 360         }
 361     }
 362 
 363     /**
 364      * Policy for detecting stuck expressions. Different criteria might cause
 365      * an expression to be judged as stuck, depending on whether the check
 366      * is performed during overload resolution or after most specific.
 367      */
 368     interface DeferredStuckPolicy {
 369         /**
 370          * Has the policy detected that a given expression should be considered stuck?
 371          */
 372         boolean isStuck();
 373         /**
 374          * Get the set of inference variables a given expression depends upon.
 375          */
 376         Set<Type> stuckVars();
 377         /**
 378          * Get the set of inference variables which might get new constraints
 379          * if a given expression is being type-checked.
 380          */
 381         Set<Type> depVars();
 382     }
 383 
 384     /**
 385      * Basic stuck policy; an expression is never considered to be stuck.
 386      */
 387     DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
 388         @Override
 389         public boolean isStuck() {
 390             return false;
 391         }
 392         @Override
 393         public Set<Type> stuckVars() {
 394             return Collections.emptySet();
 395         }
 396         @Override
 397         public Set<Type> depVars() {
 398             return Collections.emptySet();
 399         }
 400     };
 401 
 402     /**
 403      * The 'mode' in which the deferred type is to be type-checked
 404      */
 405     public enum AttrMode {
 406         /**
 407          * A speculative type-checking round is used during overload resolution
 408          * mainly to generate constraints on inference variables. Side-effects
 409          * arising from type-checking the expression associated with the deferred
 410          * type are reversed after the speculative round finishes. This means the
 411          * expression tree will be left in a blank state.
 412          */
 413         SPECULATIVE,
 414         /**
 415          * This is the plain type-checking mode. Produces side-effects on the underlying AST node
 416          */
 417         CHECK
 418     }
 419 
 420     /**
 421      * Performs speculative attribution of a lambda body and returns the speculative lambda tree,
 422      * in the absence of a target-type. Since {@link Attr#visitLambda(JCLambda)} cannot type-check
 423      * lambda bodies w/o a suitable target-type, this routine 'unrolls' the lambda by turning it
 424      * into a regular block, speculatively type-checks the block and then puts back the pieces.
 425      */
 426     JCLambda attribSpeculativeLambda(JCLambda that, Env<AttrContext> env, ResultInfo resultInfo) {
 427         ListBuffer<JCStatement> stats = new ListBuffer<>();
 428         stats.addAll(that.params);
 429         if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
 430             stats.add(make.Return((JCExpression)that.body));
 431         } else {
 432             stats.add((JCBlock)that.body);
 433         }
 434         JCBlock lambdaBlock = make.at(that.pos).Block(0, stats.toList());
 435         Env<AttrContext> localEnv = attr.lambdaEnv(that, env);
 436         try {
 437             localEnv.info.returnResult = resultInfo;
 438             JCBlock speculativeTree = (JCBlock)attribSpeculative(lambdaBlock, localEnv, resultInfo);
 439             List<JCVariableDecl> args = speculativeTree.getStatements().stream()
 440                     .filter(s -> s.hasTag(Tag.VARDEF))
 441                     .map(t -> (JCVariableDecl)t)
 442                     .collect(List.collector());
 443             JCTree lambdaBody = speculativeTree.getStatements().last();
 444             if (lambdaBody.hasTag(Tag.RETURN)) {
 445                 lambdaBody = ((JCReturn)lambdaBody).expr;
 446             }
 447             JCLambda speculativeLambda = make.Lambda(args, lambdaBody);
 448             attr.preFlow(speculativeLambda);
 449             flow.analyzeLambda(env, speculativeLambda, make, false);
 450             return speculativeLambda;
 451         } finally {
 452             localEnv.info.scope.leave();
 453         }
 454     }
 455 
 456     /**
 457      * Routine that performs speculative type-checking; the input AST node is
 458      * cloned (to avoid side-effects cause by Attr) and compiler state is
 459      * restored after type-checking. All diagnostics (but critical ones) are
 460      * disabled during speculative type-checking.
 461      */
 462     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
 463         /* When performing speculative attribution on an argument expression, we should make sure that argument type
 464          * cache does not get polluted with local types, as that leads to spurious type errors (see JDK-8295019)
 465          */
 466         return attribSpeculative(tree, env, resultInfo, treeCopier,
 467                 null, AttributionMode.SPECULATIVE, !hasTypeDeclaration(tree) ? null : argumentAttr.withLocalCacheContext());
 468     }
 469 
 470     // where
 471         private boolean hasTypeDeclaration(JCTree tree) {
 472             TypeDeclVisitor typeDeclVisitor = new TypeDeclVisitor();
 473             typeDeclVisitor.scan(tree);
 474             return typeDeclVisitor.result;
 475         }
 476 
 477         private static class TypeDeclVisitor extends TreeScanner {
 478             boolean result = false;
 479 
 480             @Override
 481             public void visitClassDef(JCClassDecl that) {
 482                 result = true;
 483             }
 484         }
 485 
 486     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, LocalCacheContext localCache) {
 487         return attribSpeculative(tree, env, resultInfo, treeCopier,
 488                 null, AttributionMode.SPECULATIVE, localCache);
 489     }
 490 
 491     <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
 492                                  Supplier<DiagnosticHandler> diagHandlerCreator, AttributionMode attributionMode,
 493                                  LocalCacheContext localCache) {
 494         final JCTree newTree = deferredCopier.copy(tree);
 495         return attribSpeculative(newTree, env, resultInfo, diagHandlerCreator, attributionMode, localCache);
 496     }
 497 
 498     /**
 499      * Attribute the given tree, mostly reverting side-effects applied to shared
 500      * compiler state. Exceptions include the ArgumentAttr.argumentTypeCache,
 501      * changes to which may be preserved if localCache is null and errors reported
 502      * outside of the speculatively attributed tree.
 503      */
 504     <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo,
 505                               Supplier<DiagnosticHandler> diagHandlerCreator, AttributionMode attributionMode,
 506                               LocalCacheContext localCache) {
 507         Env<AttrContext> speculativeEnv = env.dup(tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
 508         speculativeEnv.info.attributionMode = attributionMode;
 509         Log.DiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator != null ? diagHandlerCreator.get() : new DeferredAttrDiagHandler(log, tree);
 510         DeferredCompletionFailureHandler.Handler prevCFHandler = dcfh.setHandler(dcfh.speculativeCodeHandler);
 511         Queues prevQueues = annotate.setQueues(new Queues());
 512         int nwarnings = log.nwarnings;
 513         log.nwarnings = 0;
 514         try {
 515             attr.attribTree(tree, speculativeEnv, resultInfo);
 516             return tree;
 517         } finally {
 518             annotate.setQueues(prevQueues);
 519             dcfh.setHandler(prevCFHandler);
 520             log.nwarnings += nwarnings;
 521             enter.unenter(env.toplevel, tree);
 522             log.popDiagnosticHandler(deferredDiagnosticHandler);
 523             if (localCache != null) {
 524                 localCache.leave();
 525             }
 526         }
 527     }
 528     //where
 529         static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
 530 
 531             static class PosScanner extends TreeScanner {
 532                 DiagnosticPosition pos;
 533                 boolean found = false;
 534 
 535                 PosScanner(DiagnosticPosition pos) {
 536                     this.pos = pos;
 537                 }
 538 
 539                 @Override
 540                 public void scan(JCTree tree) {
 541                     if (tree != null &&
 542                             tree.pos() == pos) {
 543                         found = true;
 544                     }
 545                     super.scan(tree);
 546                 }
 547             }
 548 
 549             DeferredAttrDiagHandler(Log log, JCTree newTree) {
 550                 super(log, d -> {
 551                     PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
 552                     posScanner.scan(newTree);
 553                     return posScanner.found;
 554                 });
 555             }
 556         }
 557 
 558     /**
 559      * A deferred context is created on each method check. A deferred context is
 560      * used to keep track of information associated with the method check, such as
 561      * the symbol of the method being checked, the overload resolution phase,
 562      * the kind of attribution mode to be applied to deferred types and so forth.
 563      * As deferred types are processed (by the method check routine) stuck AST nodes
 564      * are added (as new deferred attribution nodes) to this context. The complete()
 565      * routine makes sure that all pending nodes are properly processed, by
 566      * progressively instantiating all inference variables on which one or more
 567      * deferred attribution node is stuck.
 568      */
 569     class DeferredAttrContext {
 570 
 571         /** attribution mode */
 572         final AttrMode mode;
 573 
 574         /** symbol of the method being checked */
 575         final Symbol msym;
 576 
 577         /** method resolution step */
 578         final Resolve.MethodResolutionPhase phase;
 579 
 580         /** inference context */
 581         final InferenceContext inferenceContext;
 582 
 583         /** parent deferred context */
 584         final DeferredAttrContext parent;
 585 
 586         /** Warner object to report warnings */
 587         final Warner warn;
 588 
 589         /** list of deferred attribution nodes to be processed */
 590         ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<>();
 591 
 592         DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
 593                 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
 594             this.mode = mode;
 595             this.msym = msym;
 596             this.phase = phase;
 597             this.parent = parent;
 598             this.warn = warn;
 599             this.inferenceContext = inferenceContext;
 600         }
 601 
 602         /**
 603          * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
 604          * Nodes added this way act as 'roots' for the out-of-order method checking process.
 605          */
 606         void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
 607                 DeferredStuckPolicy deferredStuckPolicy) {
 608             deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
 609         }
 610 
 611         /**
 612          * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
 613          * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
 614          * some inference variable might get eagerly instantiated so that all nodes
 615          * can be type-checked.
 616          */
 617         void complete() {
 618             while (!deferredAttrNodes.isEmpty()) {
 619                 boolean progress = false;
 620                 //scan a defensive copy of the node list - this is because a deferred
 621                 //attribution round can add new nodes to the list
 622                 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
 623                     if (deferredAttrNode.process(this)) {
 624                         deferredAttrNodes.remove(deferredAttrNode);
 625                         progress = true;
 626                     }
 627                 }
 628                 if (!progress) {
 629                     if (insideOverloadPhase()) {
 630                         for (DeferredAttrNode deferredNode: deferredAttrNodes) {
 631                             deferredNode.dt.tree.type = Type.noType;
 632                         }
 633                         return;
 634                     }
 635                     //remove all variables that have already been instantiated
 636                     //from the list of stuck variables
 637                     try {
 638                         //find stuck expression to unstuck
 639                         DeferredAttrNode toUnstuck = pickDeferredNode();
 640                         inferenceContext.solveAny(List.from(toUnstuck.deferredStuckPolicy.stuckVars()), warn);
 641                         inferenceContext.notifyChange();
 642                     } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
 643                         //this means that we are in speculative mode and the
 644                         //set of constraints are too tight for progress to be made.
 645                         //Just leave the remaining expressions as stuck.
 646                         break;
 647                     }
 648                 }
 649             }
 650         }
 651 
 652         public boolean insideOverloadPhase() {
 653             DeferredAttrContext dac = this;
 654             if (dac == emptyDeferredAttrContext) {
 655                 return false;
 656             }
 657             if (dac.mode == AttrMode.SPECULATIVE) {
 658                 return true;
 659             }
 660             return dac.parent.insideOverloadPhase();
 661         }
 662 
 663         /**
 664          * Pick the deferred node to be unstuck. First, deferred nodes are organized into a graph
 665          * (see {@code DeferredAttrContext.buildStuckGraph()}, where a node N1 depends on another node N2
 666          * if its input variable depends (as per the inference graph) on the output variables of N2
 667          * (see {@code DeferredAttrContext.canInfluence()}.
 668          *
 669          * Then, the chosen deferred node is the first strongly connected component containing exactly
 670          * one node found in such a graph. If no such component is found, the first deferred node is chosen.
 671          */
 672         DeferredAttrNode pickDeferredNode() {
 673             List<StuckNode> stuckGraph = buildStuckGraph();
 674             //compute tarjan on the stuck graph
 675             List<? extends StuckNode> csn = GraphUtils.tarjan(stuckGraph).get(0);
 676             return csn.length() == 1 ? csn.get(0).data : deferredAttrNodes.get(0);
 677         }
 678 
 679         List<StuckNode> buildStuckGraph() {
 680             //first, build inference graph
 681             infer.doIncorporation(inferenceContext, warn);
 682             InferenceGraph graph = infer.new GraphSolver(inferenceContext, types.noWarnings)
 683                     .new InferenceGraph();
 684             //then, build stuck graph
 685             List<StuckNode> nodes = deferredAttrNodes.stream()
 686                     .map(StuckNode::new)
 687                     .collect(List.collector());
 688             //init stuck expression graph; a deferred node A depends on a deferred node B iff
 689             //B's output variables can influence A's input variables.
 690             for (StuckNode sn1 : nodes) {
 691                 for (StuckNode sn2 : nodes) {
 692                     if (sn1 != sn2 && canInfluence(graph, sn2, sn1)) {
 693                         sn1.deps.add(sn2);
 694                     }
 695                 }
 696             }
 697             return nodes;
 698         }
 699 
 700         boolean canInfluence(InferenceGraph graph, StuckNode sn1, StuckNode sn2) {
 701             Set<Type> outputVars = sn1.data.deferredStuckPolicy.depVars();
 702             for (Type inputVar : sn2.data.deferredStuckPolicy.stuckVars()) {
 703                 InferenceGraph.Node inputNode = graph.findNode(inputVar);
 704                 //already solved stuck vars do not appear in the graph
 705                 if (inputNode != null) {
 706                     Set<InferenceGraph.Node> inputClosure = inputNode.closure();
 707                     if (outputVars.stream()
 708                             .map(graph::findNode)
 709                             .anyMatch(inputClosure::contains)) {
 710                         return true;
 711                     }
 712                 }
 713             }
 714             return false;
 715         }
 716 
 717         class StuckNode extends GraphUtils.TarjanNode<DeferredAttrNode, StuckNode> {
 718 
 719             Set<StuckNode> deps = new HashSet<>();
 720 
 721             StuckNode(DeferredAttrNode data) {
 722                 super(data);
 723             }
 724 
 725             @Override
 726             public DependencyKind[] getSupportedDependencyKinds() {
 727                 return new DependencyKind[] { Infer.DependencyKind.STUCK };
 728             }
 729 
 730             @Override
 731             public Collection<? extends StuckNode> getDependenciesByKind(DependencyKind dk) {
 732                 if (dk == Infer.DependencyKind.STUCK) {
 733                     return deps;
 734                 } else {
 735                     throw new IllegalStateException();
 736                 }
 737             }
 738 
 739             @Override
 740             public Iterable<? extends StuckNode> getAllDependencies() {
 741                 return deps;
 742             }
 743         }
 744     }
 745 
 746     /**
 747      * Class representing a deferred attribution node. It keeps track of
 748      * a deferred type, along with the expected target type information.
 749      */
 750     class DeferredAttrNode {
 751 
 752         /** underlying deferred type */
 753         DeferredType dt;
 754 
 755         /** underlying target type information */
 756         ResultInfo resultInfo;
 757 
 758         /** stuck policy associated with this node */
 759         DeferredStuckPolicy deferredStuckPolicy;
 760 
 761         DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
 762             this.dt = dt;
 763             this.resultInfo = resultInfo;
 764             this.deferredStuckPolicy = deferredStuckPolicy;
 765         }
 766 
 767         /**
 768          * Process a deferred attribution node.
 769          * Invariant: a stuck node cannot be processed.
 770          */
 771         @SuppressWarnings("fallthrough")
 772         boolean process(final DeferredAttrContext deferredAttrContext) {
 773             switch (deferredAttrContext.mode) {
 774                 case SPECULATIVE:
 775                     if (deferredStuckPolicy.isStuck()) {
 776                         new StructuralStuckChecker().check(dt, resultInfo, deferredAttrContext);
 777                         return true;
 778                     } else {
 779                         Assert.error("Cannot get here");
 780                     }
 781                 case CHECK:
 782                     if (deferredStuckPolicy.isStuck()) {
 783                         //stuck expression - see if we can propagate
 784                         if (deferredAttrContext.parent != emptyDeferredAttrContext &&
 785                                 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
 786                                         List.from(deferredStuckPolicy.stuckVars()))) {
 787                             deferredAttrContext.parent.addDeferredAttrNode(dt,
 788                                     resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
 789                                 @Override
 790                                 public InferenceContext inferenceContext() {
 791                                     return deferredAttrContext.parent.inferenceContext;
 792                                 }
 793                                 @Override
 794                                 public DeferredAttrContext deferredAttrContext() {
 795                                     return deferredAttrContext.parent;
 796                                 }
 797                             }), deferredStuckPolicy);
 798                             dt.tree.type = Type.stuckType;
 799                             return true;
 800                         } else {
 801                             return false;
 802                         }
 803                     } else {
 804                         Assert.check(!deferredAttrContext.insideOverloadPhase(),
 805                                 "attribution shouldn't be happening here");
 806                         ResultInfo instResultInfo =
 807                                 resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
 808                         dt.check(instResultInfo, dummyStuckPolicy);
 809                         return true;
 810                     }
 811                 default:
 812                     throw new AssertionError("Bad mode");
 813             }
 814         }
 815 
 816         /**
 817          * Structural checker for stuck expressions
 818          */
 819         class StructuralStuckChecker extends TreeScanner {
 820 
 821             ResultInfo resultInfo;
 822             InferenceContext inferenceContext;
 823             Env<AttrContext> env;
 824 
 825             public void check(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 826                 this.resultInfo = resultInfo;
 827                 this.inferenceContext = deferredAttrContext.inferenceContext;
 828                 this.env = dt.env;
 829                 dt.tree.accept(this);
 830                 dt.speculativeCache.put(stuckTree, resultInfo);
 831             }
 832 
 833             @Override
 834             public void visitLambda(JCLambda tree) {
 835                 Check.CheckContext checkContext = resultInfo.checkContext;
 836                 Type pt = resultInfo.pt;
 837                 if (!inferenceContext.inferencevars.contains(pt)) {
 838                     //must be a functional descriptor
 839                     Type descriptorType = null;
 840                     try {
 841                         descriptorType = types.findDescriptorType(pt);
 842                     } catch (Types.FunctionDescriptorLookupError ex) {
 843                         checkContext.report(null, ex.getDiagnostic());
 844                     }
 845 
 846                     if (descriptorType.getParameterTypes().length() != tree.params.length()) {
 847                         checkContext.report(tree,
 848                                 diags.fragment(Fragments.IncompatibleArgTypesInLambda));
 849                     }
 850 
 851                     Type currentReturnType = descriptorType.getReturnType();
 852                     boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
 853                     if (tree.getBodyKind() == BodyKind.EXPRESSION) {
 854                         boolean isExpressionCompatible = !returnTypeIsVoid ||
 855                             TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
 856                         if (!isExpressionCompatible) {
 857                             resultInfo.checkContext.report(tree.pos(),
 858                                 diags.fragment(Fragments.IncompatibleRetTypeInLambda(Fragments.MissingRetVal(currentReturnType))));
 859                         }
 860                     } else {
 861                         LambdaBodyStructChecker lambdaBodyChecker =
 862                                 new LambdaBodyStructChecker();
 863 
 864                         tree.body.accept(lambdaBodyChecker);
 865                         boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
 866 
 867                         if (returnTypeIsVoid) {
 868                             if (!isVoidCompatible) {
 869                                 resultInfo.checkContext.report(tree.pos(),
 870                                     diags.fragment(Fragments.UnexpectedRetVal));
 871                             }
 872                         } else {
 873                             boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
 874                                 && !canLambdaBodyCompleteNormally(tree);
 875                             if (!isValueCompatible && !isVoidCompatible) {
 876                                 log.error(tree.body.pos(),
 877                                           Errors.LambdaBodyNeitherValueNorVoidCompatible);
 878                             }
 879 
 880                             if (!isValueCompatible) {
 881                                 resultInfo.checkContext.report(tree.pos(),
 882                                     diags.fragment(Fragments.IncompatibleRetTypeInLambda(Fragments.MissingRetVal(currentReturnType))));
 883                             }
 884                         }
 885                     }
 886                 }
 887             }
 888 
 889             boolean canLambdaBodyCompleteNormally(JCLambda tree) {
 890                 List<JCVariableDecl> oldParams = tree.params;
 891                 LocalCacheContext localCacheContext = argumentAttr.withLocalCacheContext();
 892                 try {
 893                     tree.params = tree.params.stream()
 894                             .map(vd -> make.VarDef(vd.mods, vd.name, make.Erroneous(), null))
 895                             .collect(List.collector());
 896                     return attribSpeculativeLambda(tree, env, attr.unknownExprInfo).canCompleteNormally;
 897                 } finally {
 898                     localCacheContext.leave();
 899                     tree.params = oldParams;
 900                 }
 901             }
 902 
 903             @Override
 904             public void visitNewClass(JCNewClass tree) {
 905                 //do nothing
 906             }
 907 
 908             @Override
 909             public void visitApply(JCMethodInvocation tree) {
 910                 //do nothing
 911             }
 912 
 913             @Override
 914             public void visitConditional(JCTree.JCConditional tree) {
 915                 //skip tree.cond
 916                 scan(tree.truepart);
 917                 scan(tree.falsepart);
 918             }
 919 
 920             @Override
 921             public void visitSwitchExpression(JCSwitchExpression tree) {
 922                 scan(tree.cases);
 923             }
 924 
 925             @Override
 926             public void visitReference(JCMemberReference tree) {
 927                 Assert.checkNonNull(tree.getOverloadKind());
 928                 Check.CheckContext checkContext = resultInfo.checkContext;
 929                 Type pt = resultInfo.pt;
 930                 if (!inferenceContext.inferencevars.contains(pt)) {
 931                     Type descriptor = null;
 932                     try {
 933                         descriptor = types.findDescriptorType(pt);
 934                     } catch (Types.FunctionDescriptorLookupError ex) {
 935                         checkContext.report(null, ex.getDiagnostic());
 936                     }
 937                     Env<AttrContext> localEnv = env.dup(tree);
 938                     JCExpression exprTree;
 939                     exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
 940                             attr.memberReferenceQualifierResult(tree), argumentAttr.withLocalCacheContext());
 941                     ListBuffer<Type> argtypes = new ListBuffer<>();
 942                     for (Type t : descriptor.getParameterTypes()) {
 943                         argtypes.append(Type.noType);
 944                     }
 945                     JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
 946                     mref2.expr = exprTree;
 947                     Symbol lookupSym =
 948                             rs.resolveMemberReference(localEnv, mref2, exprTree.type,
 949                                     tree.name, argtypes.toList(), List.nil(), descriptor, rs.arityMethodCheck,
 950                                     inferenceContext, rs.structuralReferenceChooser).fst;
 951                     switch (lookupSym.kind) {
 952                         case WRONG_MTH:
 953                         case WRONG_MTHS:
 954                             //note: as argtypes are erroneous types, type-errors must
 955                             //have been caused by arity mismatch
 956                             checkContext.report(tree, diags.fragment(Fragments.IncompatibleArgTypesInMref));
 957                             break;
 958                         case ABSENT_MTH:
 959                         case STATICERR:
 960                             //if no method found, or method found with wrong staticness, report better message
 961                             checkContext.report(tree, ((ResolveError)lookupSym).getDiagnostic(DiagnosticType.FRAGMENT,
 962                                     tree, exprTree.type.tsym, exprTree.type, tree.name, argtypes.toList(), List.nil()));
 963                             break;
 964                     }
 965                 }
 966             }
 967         }
 968 
 969         /* This visitor looks for return statements, its analysis will determine if
 970          * a lambda body is void or value compatible. We must analyze return
 971          * statements contained in the lambda body only, thus any return statement
 972          * contained in an inner class or inner lambda body, should be ignored.
 973          */
 974         class LambdaBodyStructChecker extends TreeScanner {
 975             boolean isVoidCompatible = true;
 976             boolean isPotentiallyValueCompatible = true;
 977 
 978             @Override
 979             public void visitClassDef(JCClassDecl tree) {
 980                 // do nothing
 981             }
 982 
 983             @Override
 984             public void visitLambda(JCLambda tree) {
 985                 // do nothing
 986             }
 987 
 988             @Override
 989             public void visitNewClass(JCNewClass tree) {
 990                 // do nothing
 991             }
 992 
 993             @Override
 994             public void visitReturn(JCReturn tree) {
 995                 if (tree.expr != null) {
 996                     isVoidCompatible = false;
 997                 } else {
 998                     isPotentiallyValueCompatible = false;
 999                 }
1000             }
1001         }
1002     }
1003 
1004     /** an empty deferred attribution context - all methods throw exceptions */
1005     final DeferredAttrContext emptyDeferredAttrContext;
1006 
1007     /**
1008      * Map a list of types possibly containing one or more deferred types
1009      * into a list of ordinary types. Each deferred type D is mapped into a type T,
1010      * where T is computed by retrieving the type that has already been
1011      * computed for D during a previous deferred attribution round of the given kind.
1012      */
1013     class DeferredTypeMap<T> extends StructuralTypeMapping<T> {
1014         DeferredAttrContext deferredAttrContext;
1015 
1016         protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
1017             this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
1018                     infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
1019         }
1020 
1021         @Override
1022         public Type visitType(Type t, T p) {
1023             if (!t.hasTag(DEFERRED)) {
1024                 return super.visitType(t, p);
1025             } else {
1026                 DeferredType dt = (DeferredType)t;
1027                 return typeOf(dt, p);
1028             }
1029         }
1030 
1031         protected Type typeOf(DeferredType dt, T p) {
1032             switch (deferredAttrContext.mode) {
1033                 case CHECK:
1034                     return dt.tree.type == null ? Type.noType : dt.tree.type;
1035                 case SPECULATIVE:
1036                     return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
1037             }
1038             Assert.error();
1039             return null;
1040         }
1041     }
1042 
1043     /**
1044      * Specialized recovery deferred mapping.
1045      * Each deferred type D is mapped into a type T, where T is computed either by
1046      * (i) retrieving the type that has already been computed for D during a previous
1047      * attribution round (as before), or (ii) by synthesizing a new type R for D
1048      * (the latter step is useful in a recovery scenario).
1049      */
1050     public class RecoveryDeferredTypeMap extends DeferredTypeMap<Type> {
1051 
1052         public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
1053             super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
1054         }
1055 
1056         @Override
1057         protected Type typeOf(DeferredType dt, Type pt) {
1058             Type owntype = super.typeOf(dt, pt);
1059             return owntype == Type.noType ?
1060                         recover(dt, pt) : owntype;
1061         }
1062 
1063         @Override
1064         public Type visitMethodType(Type.MethodType t, Type pt) {
1065             if (t.hasTag(METHOD) && deferredAttrContext.mode == AttrMode.CHECK) {
1066                 Type mtype = deferredAttrContext.msym.type;
1067                 mtype = mtype.hasTag(ERROR) ? ((ErrorType)mtype).getOriginalType() : null;
1068                 if (mtype != null && mtype.hasTag(METHOD)) {
1069                     List<Type> argtypes1 = map(t.getParameterTypes(), mtype.getParameterTypes());
1070                     Type restype1 = visit(t.getReturnType(), mtype.getReturnType());
1071                     List<Type> thrown1 = map(t.getThrownTypes(), mtype.getThrownTypes());
1072                     if (argtypes1 == t.getParameterTypes() &&
1073                         restype1 == t.getReturnType() &&
1074                         thrown1 == t.getThrownTypes()) return t;
1075                     else return new MethodType(argtypes1, restype1, thrown1, t.tsym);
1076                 }
1077             }
1078             return super.visitMethodType(t, pt);
1079         }
1080 
1081         /**
1082          * Synthesize a type for a deferred type that hasn't been previously
1083          * reduced to an ordinary type. Functional deferred types and conditionals
1084          * are mapped to themselves, in order to have a richer diagnostic
1085          * representation. Remaining deferred types are attributed using
1086          * a default expected type (j.l.Object).
1087          */
1088         private Type recover(DeferredType dt, Type pt) {
1089             boolean isLambdaOrMemberRef =
1090                     dt.tree.hasTag(REFERENCE) || dt.tree.hasTag(LAMBDA);
1091             boolean needsRecoveryType =
1092                     pt == null ||
1093                             ((dt instanceof ArgumentAttr.ArgumentType<?> at) &&
1094                             at.speculativeTypes.values().stream().allMatch(type -> type.hasTag(ERROR))) ||
1095                             (isLambdaOrMemberRef && !types.isFunctionalInterface(pt));
1096             Type ptRecovery = needsRecoveryType ? Type.recoveryType: pt;
1097             dt.check(attr.new RecoveryInfo(deferredAttrContext, ptRecovery) {
1098                 @Override
1099                 protected Type check(DiagnosticPosition pos, Type found) {
1100                     return chk.checkNonVoid(pos, super.check(pos, found));
1101                 }
1102             });
1103             return super.visit(dt);
1104         }
1105 
1106         private List<Type> map(List<Type> ts, List<Type> pts) {
1107             if (ts.nonEmpty()) {
1108                 List<Type> tail1 = map(ts.tail, pts != null ? pts.tail : null);
1109                 Type t = visit(ts.head, pts != null && pts.nonEmpty() ? pts.head : null);
1110                 if (tail1 != ts.tail || t != ts.head)
1111                     return tail1.prepend(t);
1112             }
1113             return ts;
1114         }
1115     }
1116 
1117     /**
1118      * A special tree scanner that would only visit portions of a given tree.
1119      * The set of nodes visited by the scanner can be customized at construction-time.
1120      */
1121     abstract static class FilterScanner extends com.sun.tools.javac.tree.TreeScanner {
1122 
1123         final Predicate<JCTree> treeFilter;
1124 
1125         FilterScanner(final Set<JCTree.Tag> validTags) {
1126             this.treeFilter = t -> validTags.contains(t.getTag());
1127         }
1128 
1129         @Override
1130         public void scan(JCTree tree) {
1131             if (tree != null) {
1132                 if (treeFilter.test(tree)) {
1133                     super.scan(tree);
1134                 } else {
1135                     skip(tree);
1136                 }
1137             }
1138         }
1139 
1140         /**
1141          * handler that is executed when a node has been discarded
1142          */
1143         void skip(JCTree tree) {}
1144     }
1145 
1146     /**
1147      * A tree scanner suitable for visiting the target-type dependent nodes of
1148      * a given argument expression.
1149      */
1150     static class PolyScanner extends FilterScanner {
1151 
1152         PolyScanner() {
1153             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE, SWITCH_EXPRESSION));
1154         }
1155     }
1156 
1157     /**
1158      * A tree scanner suitable for visiting the target-type dependent nodes nested
1159      * within a lambda expression body.
1160      */
1161     static class LambdaReturnScanner extends FilterScanner {
1162 
1163         LambdaReturnScanner() {
1164             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
1165                     FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
1166         }
1167     }
1168 
1169     /**
1170      * A tree scanner suitable for visiting the target-type dependent nodes nested
1171      * within a switch expression body.
1172      */
1173     static class SwitchExpressionScanner extends FilterScanner {
1174 
1175         SwitchExpressionScanner() {
1176             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
1177                     FORLOOP, IF, SYNCHRONIZED, SWITCH, TRY, WHILELOOP, YIELD));
1178         }
1179     }
1180 
1181     /**
1182      * This visitor is used to check that structural expressions conform
1183      * to their target - this step is required as inference could end up
1184      * inferring types that make some of the nested expressions incompatible
1185      * with their corresponding instantiated target
1186      */
1187     class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
1188 
1189         Type pt;
1190         InferenceContext inferenceContext;
1191         Set<Type> stuckVars = new LinkedHashSet<>();
1192         Set<Type> depVars = new LinkedHashSet<>();
1193 
1194         @Override
1195         public boolean isStuck() {
1196             return !stuckVars.isEmpty();
1197         }
1198 
1199         @Override
1200         public Set<Type> stuckVars() {
1201             return stuckVars;
1202         }
1203 
1204         @Override
1205         public Set<Type> depVars() {
1206             return depVars;
1207         }
1208 
1209         public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1210             this.pt = resultInfo.pt;
1211             this.inferenceContext = resultInfo.checkContext.inferenceContext();
1212             scan(dt.tree);
1213             if (!stuckVars.isEmpty()) {
1214                 resultInfo.checkContext.inferenceContext()
1215                         .addFreeTypeListener(List.from(stuckVars), this);
1216             }
1217         }
1218 
1219         @Override
1220         public void typesInferred(InferenceContext inferenceContext) {
1221             stuckVars.clear();
1222         }
1223 
1224         @Override
1225         public void visitLambda(JCLambda tree) {
1226             if (inferenceContext.inferenceVars().contains(pt)) {
1227                 stuckVars.add(pt);
1228             }
1229             if (!types.isFunctionalInterface(pt)) {
1230                 return;
1231             }
1232             Type descType = types.findDescriptorType(pt);
1233             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1234             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
1235                     freeArgVars.nonEmpty()) {
1236                 stuckVars.addAll(freeArgVars);
1237                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1238                 depVars.addAll(inferenceContext.freeVarsIn(descType.getThrownTypes()));
1239             }
1240             scanLambdaBody(tree, descType.getReturnType());
1241         }
1242 
1243         @Override
1244         public void visitReference(JCMemberReference tree) {
1245             scan(tree.expr);
1246             if (inferenceContext.inferenceVars().contains(pt)) {
1247                 stuckVars.add(pt);
1248                 return;
1249             }
1250             if (!types.isFunctionalInterface(pt)) {
1251                 return;
1252             }
1253 
1254             Type descType = types.findDescriptorType(pt);
1255             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1256             if (freeArgVars.nonEmpty() &&
1257                     tree.getOverloadKind() != JCMemberReference.OverloadKind.UNOVERLOADED) {
1258                 stuckVars.addAll(freeArgVars);
1259                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1260                 depVars.addAll(inferenceContext.freeVarsIn(descType.getThrownTypes()));
1261             }
1262         }
1263 
1264         void scanLambdaBody(JCLambda lambda, final Type pt) {
1265             if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
1266                 Type prevPt = this.pt;
1267                 try {
1268                     this.pt = pt;
1269                     scan(lambda.body);
1270                 } finally {
1271                     this.pt = prevPt;
1272                 }
1273             } else {
1274                 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
1275                     @Override
1276                     public void visitReturn(JCReturn tree) {
1277                         if (tree.expr != null) {
1278                             Type prevPt = CheckStuckPolicy.this.pt;
1279                             try {
1280                                 CheckStuckPolicy.this.pt = pt;
1281                                 CheckStuckPolicy.this.scan(tree.expr);
1282                             } finally {
1283                                 CheckStuckPolicy.this.pt = prevPt;
1284                             }
1285                         }
1286                     }
1287                 };
1288                 lambdaScanner.scan(lambda.body);
1289             }
1290         }
1291 
1292         @Override
1293         public void visitSwitchExpression(JCSwitchExpression expr) {
1294             SwitchExpressionScanner switchScanner = new SwitchExpressionScanner() {
1295                 @Override
1296                 public void visitYield(JCYield tree) {
1297                     Type prevPt = CheckStuckPolicy.this.pt;
1298                     try {
1299                         CheckStuckPolicy.this.pt = pt;
1300                         CheckStuckPolicy.this.scan(tree.value);
1301                     } finally {
1302                         CheckStuckPolicy.this.pt = prevPt;
1303                     }
1304                 }
1305             };
1306             switchScanner.scan(expr.cases);
1307         }
1308 
1309     }
1310 
1311     /**
1312      * This visitor is used to check that structural expressions conform
1313      * to their target - this step is required as inference could end up
1314      * inferring types that make some of the nested expressions incompatible
1315      * with their corresponding instantiated target
1316      */
1317     class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
1318 
1319         boolean stuck;
1320 
1321         @Override
1322         public boolean isStuck() {
1323             return super.isStuck() || stuck;
1324         }
1325 
1326         public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1327             super(resultInfo, dt);
1328         }
1329 
1330         @Override
1331         public void visitLambda(JCLambda tree) {
1332             super.visitLambda(tree);
1333             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
1334                 stuck = true;
1335             }
1336         }
1337 
1338         @Override
1339         public void visitReference(JCMemberReference tree) {
1340             super.visitReference(tree);
1341             if (tree.getOverloadKind() != JCMemberReference.OverloadKind.UNOVERLOADED) {
1342                 stuck = true;
1343             }
1344         }
1345     }
1346 
1347     /**
1348      * Mode of attribution (used in AttrContext).
1349      */
1350     enum AttributionMode {
1351         /**Normal, non-speculative, attribution.*/
1352         FULL(false, true),
1353         /**Speculative attribution on behalf of an Analyzer.*/
1354         ATTRIB_TO_TREE(true, true),
1355         /**Speculative attribution on behalf of an Analyzer.*/
1356         ANALYZER(true, false),
1357         /**Speculative attribution.*/
1358         SPECULATIVE(true, false);
1359 
1360         AttributionMode(boolean isSpeculative, boolean recover) {
1361             this.isSpeculative = isSpeculative;
1362             this.recover = recover;
1363         }
1364 
1365         boolean isSpeculative() {
1366             return isSpeculative;
1367         }
1368 
1369         boolean recover() {
1370             return recover;
1371         }
1372 
1373         final boolean isSpeculative;
1374         final boolean recover;
1375     }
1376 }