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