1 /*
   2  * Copyright (c) 2012, 2014, 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.tools.javac.code.*;
  30 import com.sun.tools.javac.tree.*;
  31 import com.sun.tools.javac.util.*;
  32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  33 import com.sun.tools.javac.code.Symbol.*;
  34 import com.sun.tools.javac.code.Type.*;
  35 import com.sun.tools.javac.comp.Attr.ResultInfo;
  36 import com.sun.tools.javac.comp.Infer.InferenceContext;
  37 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
  38 import com.sun.tools.javac.tree.JCTree.*;
  39 
  40 import java.util.ArrayList;
  41 import java.util.Collections;
  42 import java.util.EnumSet;
  43 import java.util.LinkedHashMap;
  44 import java.util.LinkedHashSet;
  45 import java.util.Map;
  46 import java.util.Set;
  47 import java.util.WeakHashMap;
  48 
  49 import static com.sun.tools.javac.code.Kinds.VAL;
  50 import static com.sun.tools.javac.code.TypeTag.*;
  51 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  52 
  53 /**
  54  * This is an helper class that is used to perform deferred type-analysis.
  55  * Each time a poly expression occurs in argument position, javac attributes it
  56  * with a temporary 'deferred type' that is checked (possibly multiple times)
  57  * against an expected formal type.
  58  *
  59  *  <p><b>This is NOT part of any supported API.
  60  *  If you write code that depends on this, you do so at your own risk.
  61  *  This code and its internal interfaces are subject to change or
  62  *  deletion without notice.</b>
  63  */
  64 public class DeferredAttr extends JCTree.Visitor {
  65     protected static final Context.Key<DeferredAttr> deferredAttrKey = new Context.Key<>();
  66 
  67     final Attr attr;
  68     final Check chk;
  69     final JCDiagnostic.Factory diags;
  70     final Enter enter;
  71     final Infer infer;
  72     final Resolve rs;
  73     final Log log;
  74     final Symtab syms;
  75     final TreeMaker make;
  76     final Types types;
  77     final Flow flow;
  78     final Names names;
  79 
  80     public static DeferredAttr instance(Context context) {
  81         DeferredAttr instance = context.get(deferredAttrKey);
  82         if (instance == null)
  83             instance = new DeferredAttr(context);
  84         return instance;
  85     }
  86 
  87     protected DeferredAttr(Context context) {
  88         context.put(deferredAttrKey, this);
  89         attr = Attr.instance(context);
  90         chk = Check.instance(context);
  91         diags = JCDiagnostic.Factory.instance(context);
  92         enter = Enter.instance(context);
  93         infer = Infer.instance(context);
  94         rs = Resolve.instance(context);
  95         log = Log.instance(context);
  96         syms = Symtab.instance(context);
  97         make = TreeMaker.instance(context);
  98         types = Types.instance(context);
  99         flow = Flow.instance(context);
 100         names = Names.instance(context);
 101         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
 102         emptyDeferredAttrContext =
 103             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
 104                 @Override
 105                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
 106                     Assert.error("Empty deferred context!");
 107                 }
 108                 @Override
 109                 void complete() {
 110                     Assert.error("Empty deferred context!");
 111                 }
 112 
 113                 @Override
 114                 public String toString() {
 115                     return "Empty deferred context!";
 116                 }
 117             };
 118     }
 119 
 120     /** shared tree for stuck expressions */
 121     final JCTree stuckTree;
 122 
 123     /**
 124      * This type represents a deferred type. A deferred type starts off with
 125      * no information on the underlying expression type. Such info needs to be
 126      * discovered through type-checking the deferred type against a target-type.
 127      * Every deferred type keeps a pointer to the AST node from which it originated.
 128      */
 129     public class DeferredType extends Type {
 130 
 131         public JCExpression tree;
 132         Env<AttrContext> env;
 133         AttrMode mode;
 134         SpeculativeCache speculativeCache;
 135 
 136         DeferredType(JCExpression tree, Env<AttrContext> env) {
 137             super(null, noAnnotations);
 138             this.tree = tree;
 139             this.env = attr.copyEnv(env);
 140             this.speculativeCache = new SpeculativeCache();
 141         }
 142 
 143         @Override
 144         public DeferredType annotatedType(List<Attribute.TypeCompound> typeAnnotations) {
 145             throw new AssertionError("Cannot annotate a deferred type");
 146         }
 147 
 148         @Override
 149         public TypeTag getTag() {
 150             return DEFERRED;
 151         }
 152 
 153         @Override
 154         public String toString() {
 155             return "DeferredType";
 156         }
 157 
 158         /**
 159          * A speculative cache is used to keep track of all overload resolution rounds
 160          * that triggered speculative attribution on a given deferred type. Each entry
 161          * stores a pointer to the speculative tree and the resolution phase in which the entry
 162          * has been added.
 163          */
 164         class SpeculativeCache {
 165 
 166             private Map<Symbol, List<Entry>> cache = new WeakHashMap<>();
 167 
 168             class Entry {
 169                 JCTree speculativeTree;
 170                 ResultInfo resultInfo;
 171 
 172                 public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
 173                     this.speculativeTree = speculativeTree;
 174                     this.resultInfo = resultInfo;
 175                 }
 176 
 177                 boolean matches(MethodResolutionPhase phase) {
 178                     return resultInfo.checkContext.deferredAttrContext().phase == phase;
 179                 }
 180             }
 181 
 182             /**
 183              * Retrieve a speculative cache entry corresponding to given symbol
 184              * and resolution phase
 185              */
 186             Entry get(Symbol msym, MethodResolutionPhase phase) {
 187                 List<Entry> entries = cache.get(msym);
 188                 if (entries == null) return null;
 189                 for (Entry e : entries) {
 190                     if (e.matches(phase)) return e;
 191                 }
 192                 return null;
 193             }
 194 
 195             /**
 196              * Stores a speculative cache entry corresponding to given symbol
 197              * and resolution phase
 198              */
 199             void put(JCTree speculativeTree, ResultInfo resultInfo) {
 200                 Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
 201                 List<Entry> entries = cache.get(msym);
 202                 if (entries == null) {
 203                     entries = List.nil();
 204                 }
 205                 cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
 206             }
 207         }
 208 
 209         /**
 210          * Get the type that has been computed during a speculative attribution round
 211          */
 212         Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
 213             SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
 214             return e != null ? e.speculativeTree.type : Type.noType;
 215         }
 216 
 217         /**
 218          * Check a deferred type against a potential target-type. Depending on
 219          * the current attribution mode, a normal vs. speculative attribution
 220          * round is performed on the underlying AST node. There can be only one
 221          * speculative round for a given target method symbol; moreover, a normal
 222          * attribution round must follow one or more speculative rounds.
 223          */
 224         Type check(ResultInfo resultInfo) {
 225             DeferredStuckPolicy deferredStuckPolicy;
 226             if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
 227                 deferredStuckPolicy = dummyStuckPolicy;
 228             } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE) {
 229                 deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
 230             } else {
 231                 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
 232             }
 233             return check(resultInfo, deferredStuckPolicy, basicCompleter);
 234         }
 235 
 236         private Type check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy,
 237                 DeferredTypeCompleter deferredTypeCompleter) {
 238             DeferredAttrContext deferredAttrContext =
 239                     resultInfo.checkContext.deferredAttrContext();
 240             Assert.check(deferredAttrContext != emptyDeferredAttrContext);
 241             if (deferredStuckPolicy.isStuck()) {
 242                 deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
 243                 return Type.noType;
 244             } else {
 245                 try {
 246                     return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext);
 247                 } finally {
 248                     mode = deferredAttrContext.mode;
 249                 }
 250             }
 251         }
 252     }
 253 
 254     /**
 255      * A completer for deferred types. Defines an entry point for type-checking
 256      * a deferred type.
 257      */
 258     interface DeferredTypeCompleter {
 259         /**
 260          * Entry point for type-checking a deferred type. Depending on the
 261          * circumstances, type-checking could amount to full attribution
 262          * or partial structural check (aka potential applicability).
 263          */
 264         Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext);
 265     }
 266 
 267 
 268     /**
 269      * A basic completer for deferred types. This completer type-checks a deferred type
 270      * using attribution; depending on the attribution mode, this could be either standard
 271      * or speculative attribution.
 272      */
 273     DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() {
 274         public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 275             switch (deferredAttrContext.mode) {
 276                 case SPECULATIVE:
 277                     //Note: if a symbol is imported twice we might do two identical
 278                     //speculative rounds...
 279                     Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE);
 280                     JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo);
 281                     dt.speculativeCache.put(speculativeTree, resultInfo);
 282                     return speculativeTree.type;
 283                 case CHECK:
 284                     Assert.check(dt.mode != null);
 285                     return attr.attribTree(dt.tree, dt.env, resultInfo);
 286             }
 287             Assert.error();
 288             return null;
 289         }
 290     };
 291 
 292     DeferredTypeCompleter dummyCompleter = new DeferredTypeCompleter() {
 293         public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 294             Assert.check(deferredAttrContext.mode == AttrMode.CHECK);
 295             return dt.tree.type = Type.stuckType;
 296         }
 297     };
 298 
 299     /**
 300      * Policy for detecting stuck expressions. Different criteria might cause
 301      * an expression to be judged as stuck, depending on whether the check
 302      * is performed during overload resolution or after most specific.
 303      */
 304     interface DeferredStuckPolicy {
 305         /**
 306          * Has the policy detected that a given expression should be considered stuck?
 307          */
 308         boolean isStuck();
 309         /**
 310          * Get the set of inference variables a given expression depends upon.
 311          */
 312         Set<Type> stuckVars();
 313         /**
 314          * Get the set of inference variables which might get new constraints
 315          * if a given expression is being type-checked.
 316          */
 317         Set<Type> depVars();
 318     }
 319 
 320     /**
 321      * Basic stuck policy; an expression is never considered to be stuck.
 322      */
 323     DeferredStuckPolicy dummyStuckPolicy = new DeferredStuckPolicy() {
 324         @Override
 325         public boolean isStuck() {
 326             return false;
 327         }
 328         @Override
 329         public Set<Type> stuckVars() {
 330             return Collections.emptySet();
 331         }
 332         @Override
 333         public Set<Type> depVars() {
 334             return Collections.emptySet();
 335         }
 336     };
 337 
 338     /**
 339      * The 'mode' in which the deferred type is to be type-checked
 340      */
 341     public enum AttrMode {
 342         /**
 343          * A speculative type-checking round is used during overload resolution
 344          * mainly to generate constraints on inference variables. Side-effects
 345          * arising from type-checking the expression associated with the deferred
 346          * type are reversed after the speculative round finishes. This means the
 347          * expression tree will be left in a blank state.
 348          */
 349         SPECULATIVE,
 350         /**
 351          * This is the plain type-checking mode. Produces side-effects on the underlying AST node
 352          */
 353         CHECK
 354     }
 355 
 356     /**
 357      * Routine that performs speculative type-checking; the input AST node is
 358      * cloned (to avoid side-effects cause by Attr) and compiler state is
 359      * restored after type-checking. All diagnostics (but critical ones) are
 360      * disabled during speculative type-checking.
 361      */
 362     JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
 363         final JCTree newTree = new TreeCopier<>(make).copy(tree);
 364         Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared()));
 365         speculativeEnv.info.scope.owner = env.info.scope.owner;
 366         Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
 367                 new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
 368             public boolean accepts(final JCDiagnostic d) {
 369                 class PosScanner extends TreeScanner {
 370                     boolean found = false;
 371 
 372                     @Override
 373                     public void scan(JCTree tree) {
 374                         if (tree != null &&
 375                                 tree.pos() == d.getDiagnosticPosition()) {
 376                             found = true;
 377                         }
 378                         super.scan(tree);
 379                     }
 380                 }
 381                 PosScanner posScanner = new PosScanner();
 382                 posScanner.scan(newTree);
 383                 return posScanner.found;
 384             }
 385         });
 386         try {
 387             attr.attribTree(newTree, speculativeEnv, resultInfo);
 388             unenterScanner.scan(newTree);
 389             return newTree;
 390         } finally {
 391             unenterScanner.scan(newTree);
 392             log.popDiagnosticHandler(deferredDiagnosticHandler);
 393         }
 394     }
 395     //where
 396         protected UnenterScanner unenterScanner = new UnenterScanner();
 397 
 398         class UnenterScanner extends TreeScanner {
 399             @Override
 400             public void visitClassDef(JCClassDecl tree) {
 401                 ClassSymbol csym = tree.sym;
 402                 //if something went wrong during method applicability check
 403                 //it is possible that nested expressions inside argument expression
 404                 //are left unchecked - in such cases there's nothing to clean up.
 405                 if (csym == null) return;
 406                 enter.typeEnvs.remove(csym);
 407                 chk.compiled.remove(csym.flatname);
 408                 syms.classes.remove(csym.flatname);
 409                 super.visitClassDef(tree);
 410             }
 411         }
 412 
 413     /**
 414      * A deferred context is created on each method check. A deferred context is
 415      * used to keep track of information associated with the method check, such as
 416      * the symbol of the method being checked, the overload resolution phase,
 417      * the kind of attribution mode to be applied to deferred types and so forth.
 418      * As deferred types are processed (by the method check routine) stuck AST nodes
 419      * are added (as new deferred attribution nodes) to this context. The complete()
 420      * routine makes sure that all pending nodes are properly processed, by
 421      * progressively instantiating all inference variables on which one or more
 422      * deferred attribution node is stuck.
 423      */
 424     class DeferredAttrContext {
 425 
 426         /** attribution mode */
 427         final AttrMode mode;
 428 
 429         /** symbol of the method being checked */
 430         final Symbol msym;
 431 
 432         /** method resolution step */
 433         final Resolve.MethodResolutionPhase phase;
 434 
 435         /** inference context */
 436         final InferenceContext inferenceContext;
 437 
 438         /** parent deferred context */
 439         final DeferredAttrContext parent;
 440 
 441         /** Warner object to report warnings */
 442         final Warner warn;
 443 
 444         /** list of deferred attribution nodes to be processed */
 445         ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<>();
 446 
 447         DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase,
 448                 InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn) {
 449             this.mode = mode;
 450             this.msym = msym;
 451             this.phase = phase;
 452             this.parent = parent;
 453             this.warn = warn;
 454             this.inferenceContext = inferenceContext;
 455         }
 456 
 457         /**
 458          * Adds a node to the list of deferred attribution nodes - used by Resolve.rawCheckArgumentsApplicable
 459          * Nodes added this way act as 'roots' for the out-of-order method checking process.
 460          */
 461         void addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo,
 462                 DeferredStuckPolicy deferredStuckPolicy) {
 463             deferredAttrNodes.add(new DeferredAttrNode(dt, resultInfo, deferredStuckPolicy));
 464         }
 465 
 466         /**
 467          * Incrementally process all nodes, by skipping 'stuck' nodes and attributing
 468          * 'unstuck' ones. If at any point no progress can be made (no 'unstuck' nodes)
 469          * some inference variable might get eagerly instantiated so that all nodes
 470          * can be type-checked.
 471          */
 472         void complete() {
 473             while (!deferredAttrNodes.isEmpty()) {
 474                 Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<>();
 475                 List<Type> stuckVars = List.nil();
 476                 boolean progress = false;
 477                 //scan a defensive copy of the node list - this is because a deferred
 478                 //attribution round can add new nodes to the list
 479                 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
 480                     if (!deferredAttrNode.process(this)) {
 481                         List<Type> restStuckVars =
 482                                 List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
 483                                 .intersect(inferenceContext.restvars());
 484                         stuckVars = stuckVars.prependList(restStuckVars);
 485                         //update dependency map
 486                         for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
 487                                 .intersect(inferenceContext.restvars())) {
 488                             Set<Type> prevDeps = depVarsMap.get(t);
 489                             if (prevDeps == null) {
 490                                 prevDeps = new LinkedHashSet<>();
 491                                 depVarsMap.put(t, prevDeps);
 492                             }
 493                             prevDeps.addAll(restStuckVars);
 494                         }
 495                     } else {
 496                         deferredAttrNodes.remove(deferredAttrNode);
 497                         progress = true;
 498                     }
 499                 }
 500                 if (!progress) {
 501                     DeferredAttrContext dac = this;
 502                     while (dac != emptyDeferredAttrContext) {
 503                         if (dac.mode == AttrMode.SPECULATIVE) {
 504                             //unsticking does not take place during overload
 505                             break;
 506                         }
 507                         dac = dac.parent;
 508                     }
 509                     //remove all variables that have already been instantiated
 510                     //from the list of stuck variables
 511                     try {
 512                         inferenceContext.solveAny(stuckVars, depVarsMap, warn);
 513                         inferenceContext.notifyChange();
 514                     } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
 515                         //this means that we are in speculative mode and the
 516                         //set of contraints are too tight for progess to be made.
 517                         //Just leave the remaining expressions as stuck.
 518                         break;
 519                     }
 520                 }
 521             }
 522         }
 523     }
 524 
 525     /**
 526      * Class representing a deferred attribution node. It keeps track of
 527      * a deferred type, along with the expected target type information.
 528      */
 529     class DeferredAttrNode {
 530 
 531         /** underlying deferred type */
 532         DeferredType dt;
 533 
 534         /** underlying target type information */
 535         ResultInfo resultInfo;
 536 
 537         /** stuck policy associated with this node */
 538         DeferredStuckPolicy deferredStuckPolicy;
 539 
 540         DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
 541             this.dt = dt;
 542             this.resultInfo = resultInfo;
 543             this.deferredStuckPolicy = deferredStuckPolicy;
 544         }
 545 
 546         /**
 547          * Process a deferred attribution node.
 548          * Invariant: a stuck node cannot be processed.
 549          */
 550         @SuppressWarnings("fallthrough")
 551         boolean process(final DeferredAttrContext deferredAttrContext) {
 552             switch (deferredAttrContext.mode) {
 553                 case SPECULATIVE:
 554                     if (deferredStuckPolicy.isStuck()) {
 555                         dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
 556                         return true;
 557                     } else {
 558                         Assert.error("Cannot get here");
 559                     }
 560                 case CHECK:
 561                     if (deferredStuckPolicy.isStuck()) {
 562                         //stuck expression - see if we can propagate
 563                         if (deferredAttrContext.parent != emptyDeferredAttrContext &&
 564                                 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
 565                                         List.from(deferredStuckPolicy.stuckVars()))) {
 566                             deferredAttrContext.parent.addDeferredAttrNode(dt,
 567                                     resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
 568                                 @Override
 569                                 public InferenceContext inferenceContext() {
 570                                     return deferredAttrContext.parent.inferenceContext;
 571                                 }
 572                                 @Override
 573                                 public DeferredAttrContext deferredAttrContext() {
 574                                     return deferredAttrContext.parent;
 575                                 }
 576                             }), deferredStuckPolicy);
 577                             dt.tree.type = Type.stuckType;
 578                             return true;
 579                         } else {
 580                             return false;
 581                         }
 582                     } else {
 583                         ResultInfo instResultInfo =
 584                                 resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
 585                         dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
 586                         return true;
 587                     }
 588                 default:
 589                     throw new AssertionError("Bad mode");
 590             }
 591         }
 592 
 593         /**
 594          * Structural checker for stuck expressions
 595          */
 596         class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
 597 
 598             ResultInfo resultInfo;
 599             InferenceContext inferenceContext;
 600             Env<AttrContext> env;
 601 
 602             public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
 603                 this.resultInfo = resultInfo;
 604                 this.inferenceContext = deferredAttrContext.inferenceContext;
 605                 this.env = dt.env;
 606                 dt.tree.accept(this);
 607                 dt.speculativeCache.put(stuckTree, resultInfo);
 608                 return Type.noType;
 609             }
 610 
 611             @Override
 612             public void visitLambda(JCLambda tree) {
 613                 Check.CheckContext checkContext = resultInfo.checkContext;
 614                 Type pt = resultInfo.pt;
 615                 if (!inferenceContext.inferencevars.contains(pt)) {
 616                     //must be a functional descriptor
 617                     Type descriptorType = null;
 618                     try {
 619                         descriptorType = types.findDescriptorType(pt);
 620                     } catch (Types.FunctionDescriptorLookupError ex) {
 621                         checkContext.report(null, ex.getDiagnostic());
 622                     }
 623 
 624                     if (descriptorType.getParameterTypes().length() != tree.params.length()) {
 625                         checkContext.report(tree,
 626                                 diags.fragment("incompatible.arg.types.in.lambda"));
 627                     }
 628 
 629                     Type currentReturnType = descriptorType.getReturnType();
 630                     boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
 631                     if (tree.getBodyKind() == BodyKind.EXPRESSION) {
 632                         boolean isExpressionCompatible = !returnTypeIsVoid ||
 633                             TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
 634                         if (!isExpressionCompatible) {
 635                             resultInfo.checkContext.report(tree.pos(),
 636                                 diags.fragment("incompatible.ret.type.in.lambda",
 637                                     diags.fragment("missing.ret.val", currentReturnType)));
 638                         }
 639                     } else {
 640                         LambdaBodyStructChecker lambdaBodyChecker =
 641                                 new LambdaBodyStructChecker();
 642 
 643                         tree.body.accept(lambdaBodyChecker);
 644                         boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
 645 
 646                         if (returnTypeIsVoid) {
 647                             if (!isVoidCompatible) {
 648                                 resultInfo.checkContext.report(tree.pos(),
 649                                     diags.fragment("unexpected.ret.val"));
 650                             }
 651                         } else {
 652                             boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
 653                                 && !canLambdaBodyCompleteNormally(tree);
 654                             if (!isValueCompatible && !isVoidCompatible) {
 655                                 log.error(tree.body.pos(),
 656                                     "lambda.body.neither.value.nor.void.compatible");
 657                             }
 658 
 659                             if (!isValueCompatible) {
 660                                 resultInfo.checkContext.report(tree.pos(),
 661                                     diags.fragment("incompatible.ret.type.in.lambda",
 662                                         diags.fragment("missing.ret.val", currentReturnType)));
 663                             }
 664                         }
 665                     }
 666                 }
 667             }
 668 
 669             boolean canLambdaBodyCompleteNormally(JCLambda tree) {
 670                 JCLambda newTree = new TreeCopier<>(make).copy(tree);
 671                 /* attr.lambdaEnv will create a meaningful env for the
 672                  * lambda expression. This is specially useful when the
 673                  * lambda is used as the init of a field. But we need to
 674                  * remove any added symbol.
 675                  */
 676                 Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
 677                 try {
 678                     List<JCVariableDecl> tmpParams = newTree.params;
 679                     while (tmpParams.nonEmpty()) {
 680                         tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
 681                         tmpParams = tmpParams.tail;
 682                     }
 683 
 684                     attr.attribStats(newTree.params, localEnv);
 685 
 686                     /* set pt to Type.noType to avoid generating any bound
 687                      * which may happen if lambda's return type is an
 688                      * inference variable
 689                      */
 690                     Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(VAL, Type.noType);
 691                     localEnv.info.returnResult = bodyResultInfo;
 692 
 693                     // discard any log output
 694                     Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 695                     try {
 696                         JCBlock body = (JCBlock)newTree.body;
 697                         /* we need to attribute the lambda body before
 698                          * doing the aliveness analysis. This is because
 699                          * constant folding occurs during attribution
 700                          * and the reachability of some statements depends
 701                          * on constant values, for example:
 702                          *
 703                          *     while (true) {...}
 704                          */
 705                         attr.attribStats(body.stats, localEnv);
 706 
 707                         attr.preFlow(newTree);
 708                         /* make an aliveness / reachability analysis of the lambda
 709                          * to determine if it can complete normally
 710                          */
 711                         flow.analyzeLambda(localEnv, newTree, make, true);
 712                     } finally {
 713                         log.popDiagnosticHandler(diagHandler);
 714                     }
 715                     return newTree.canCompleteNormally;
 716                 } finally {
 717                     JCBlock body = (JCBlock)newTree.body;
 718                     unenterScanner.scan(body.stats);
 719                     localEnv.info.scope.leave();
 720                 }
 721             }
 722 
 723             @Override
 724             public void visitNewClass(JCNewClass tree) {
 725                 //do nothing
 726             }
 727 
 728             @Override
 729             public void visitApply(JCMethodInvocation tree) {
 730                 //do nothing
 731             }
 732 
 733             @Override
 734             public void visitReference(JCMemberReference tree) {
 735                 Check.CheckContext checkContext = resultInfo.checkContext;
 736                 Type pt = resultInfo.pt;
 737                 if (!inferenceContext.inferencevars.contains(pt)) {
 738                     try {
 739                         types.findDescriptorType(pt);
 740                     } catch (Types.FunctionDescriptorLookupError ex) {
 741                         checkContext.report(null, ex.getDiagnostic());
 742                     }
 743                     Env<AttrContext> localEnv = env.dup(tree);
 744                     JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
 745                             attr.memberReferenceQualifierResult(tree));
 746                     ListBuffer<Type> argtypes = new ListBuffer<>();
 747                     for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
 748                         argtypes.append(Type.noType);
 749                     }
 750                     JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
 751                     mref2.expr = exprTree;
 752                     Symbol lookupSym =
 753                             rs.resolveMemberReferenceByArity(localEnv, mref2, exprTree.type,
 754                                 tree.name, argtypes.toList(), inferenceContext);
 755                     switch (lookupSym.kind) {
 756                         //note: as argtypes are erroneous types, type-errors must
 757                         //have been caused by arity mismatch
 758                         case Kinds.ABSENT_MTH:
 759                         case Kinds.WRONG_MTH:
 760                         case Kinds.WRONG_MTHS:
 761                         case Kinds.WRONG_STATICNESS:
 762                            checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
 763                     }
 764                 }
 765             }
 766         }
 767 
 768         /* This visitor looks for return statements, its analysis will determine if
 769          * a lambda body is void or value compatible. We must analyze return
 770          * statements contained in the lambda body only, thus any return statement
 771          * contained in an inner class or inner lambda body, should be ignored.
 772          */
 773         class LambdaBodyStructChecker extends TreeScanner {
 774             boolean isVoidCompatible = true;
 775             boolean isPotentiallyValueCompatible = true;
 776 
 777             @Override
 778             public void visitClassDef(JCClassDecl tree) {
 779                 // do nothing
 780             }
 781 
 782             @Override
 783             public void visitLambda(JCLambda tree) {
 784                 // do nothing
 785             }
 786 
 787             @Override
 788             public void visitNewClass(JCNewClass tree) {
 789                 // do nothing
 790             }
 791 
 792             @Override
 793             public void visitReturn(JCReturn tree) {
 794                 if (tree.expr != null) {
 795                     isVoidCompatible = false;
 796                 } else {
 797                     isPotentiallyValueCompatible = false;
 798                 }
 799             }
 800         }
 801     }
 802 
 803     /** an empty deferred attribution context - all methods throw exceptions */
 804     final DeferredAttrContext emptyDeferredAttrContext;
 805 
 806     /**
 807      * Map a list of types possibly containing one or more deferred types
 808      * into a list of ordinary types. Each deferred type D is mapped into a type T,
 809      * where T is computed by retrieving the type that has already been
 810      * computed for D during a previous deferred attribution round of the given kind.
 811      */
 812     class DeferredTypeMap extends Type.Mapping {
 813 
 814         DeferredAttrContext deferredAttrContext;
 815 
 816         protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
 817             super(String.format("deferredTypeMap[%s]", mode));
 818             this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
 819                     infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
 820         }
 821 
 822         @Override
 823         public Type apply(Type t) {
 824             if (!t.hasTag(DEFERRED)) {
 825                 return t.map(this);
 826             } else {
 827                 DeferredType dt = (DeferredType)t;
 828                 return typeOf(dt);
 829             }
 830         }
 831 
 832         protected Type typeOf(DeferredType dt) {
 833             switch (deferredAttrContext.mode) {
 834                 case CHECK:
 835                     return dt.tree.type == null ? Type.noType : dt.tree.type;
 836                 case SPECULATIVE:
 837                     return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
 838             }
 839             Assert.error();
 840             return null;
 841         }
 842     }
 843 
 844     /**
 845      * Specialized recovery deferred mapping.
 846      * Each deferred type D is mapped into a type T, where T is computed either by
 847      * (i) retrieving the type that has already been computed for D during a previous
 848      * attribution round (as before), or (ii) by synthesizing a new type R for D
 849      * (the latter step is useful in a recovery scenario).
 850      */
 851     public class RecoveryDeferredTypeMap extends DeferredTypeMap {
 852 
 853         public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
 854             super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
 855         }
 856 
 857         @Override
 858         protected Type typeOf(DeferredType dt) {
 859             Type owntype = super.typeOf(dt);
 860             return owntype == Type.noType ?
 861                         recover(dt) : owntype;
 862         }
 863 
 864         /**
 865          * Synthesize a type for a deferred type that hasn't been previously
 866          * reduced to an ordinary type. Functional deferred types and conditionals
 867          * are mapped to themselves, in order to have a richer diagnostic
 868          * representation. Remaining deferred types are attributed using
 869          * a default expected type (j.l.Object).
 870          */
 871         private Type recover(DeferredType dt) {
 872             dt.check(attr.new RecoveryInfo(deferredAttrContext) {
 873                 @Override
 874                 protected Type check(DiagnosticPosition pos, Type found) {
 875                     return chk.checkNonVoid(pos, super.check(pos, found));
 876                 }
 877             });
 878             return super.apply(dt);
 879         }
 880     }
 881 
 882     /**
 883      * A special tree scanner that would only visit portions of a given tree.
 884      * The set of nodes visited by the scanner can be customized at construction-time.
 885      */
 886     abstract static class FilterScanner extends TreeScanner {
 887 
 888         final Filter<JCTree> treeFilter;
 889 
 890         FilterScanner(final Set<JCTree.Tag> validTags) {
 891             this.treeFilter = new Filter<JCTree>() {
 892                 public boolean accepts(JCTree t) {
 893                     return validTags.contains(t.getTag());
 894                 }
 895             };
 896         }
 897 
 898         @Override
 899         public void scan(JCTree tree) {
 900             if (tree != null) {
 901                 if (treeFilter.accepts(tree)) {
 902                     super.scan(tree);
 903                 } else {
 904                     skip(tree);
 905                 }
 906             }
 907         }
 908 
 909         /**
 910          * handler that is executed when a node has been discarded
 911          */
 912         void skip(JCTree tree) {}
 913     }
 914 
 915     /**
 916      * A tree scanner suitable for visiting the target-type dependent nodes of
 917      * a given argument expression.
 918      */
 919     static class PolyScanner extends FilterScanner {
 920 
 921         PolyScanner() {
 922             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
 923         }
 924     }
 925 
 926     /**
 927      * A tree scanner suitable for visiting the target-type dependent nodes nested
 928      * within a lambda expression body.
 929      */
 930     static class LambdaReturnScanner extends FilterScanner {
 931 
 932         LambdaReturnScanner() {
 933             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
 934                     FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
 935         }
 936     }
 937 
 938     /**
 939      * This visitor is used to check that structural expressions conform
 940      * to their target - this step is required as inference could end up
 941      * inferring types that make some of the nested expressions incompatible
 942      * with their corresponding instantiated target
 943      */
 944     class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
 945 
 946         Type pt;
 947         Infer.InferenceContext inferenceContext;
 948         Set<Type> stuckVars = new LinkedHashSet<>();
 949         Set<Type> depVars = new LinkedHashSet<>();
 950 
 951         @Override
 952         public boolean isStuck() {
 953             return !stuckVars.isEmpty();
 954         }
 955 
 956         @Override
 957         public Set<Type> stuckVars() {
 958             return stuckVars;
 959         }
 960 
 961         @Override
 962         public Set<Type> depVars() {
 963             return depVars;
 964         }
 965 
 966         public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
 967             this.pt = resultInfo.pt;
 968             this.inferenceContext = resultInfo.checkContext.inferenceContext();
 969             scan(dt.tree);
 970             if (!stuckVars.isEmpty()) {
 971                 resultInfo.checkContext.inferenceContext()
 972                         .addFreeTypeListener(List.from(stuckVars), this);
 973             }
 974         }
 975 
 976         @Override
 977         public void typesInferred(InferenceContext inferenceContext) {
 978             stuckVars.clear();
 979         }
 980 
 981         @Override
 982         public void visitLambda(JCLambda tree) {
 983             if (inferenceContext.inferenceVars().contains(pt)) {
 984                 stuckVars.add(pt);
 985             }
 986             if (!types.isFunctionalInterface(pt)) {
 987                 return;
 988             }
 989             Type descType = types.findDescriptorType(pt);
 990             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
 991             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
 992                     freeArgVars.nonEmpty()) {
 993                 stuckVars.addAll(freeArgVars);
 994                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
 995             }
 996             scanLambdaBody(tree, descType.getReturnType());
 997         }
 998 
 999         @Override
1000         public void visitReference(JCMemberReference tree) {
1001             scan(tree.expr);
1002             if (inferenceContext.inferenceVars().contains(pt)) {
1003                 stuckVars.add(pt);
1004                 return;
1005             }
1006             if (!types.isFunctionalInterface(pt)) {
1007                 return;
1008             }
1009 
1010             Type descType = types.findDescriptorType(pt);
1011             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
1012             if (freeArgVars.nonEmpty() &&
1013                     tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1014                 stuckVars.addAll(freeArgVars);
1015                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
1016             }
1017         }
1018 
1019         void scanLambdaBody(JCLambda lambda, final Type pt) {
1020             if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
1021                 Type prevPt = this.pt;
1022                 try {
1023                     this.pt = pt;
1024                     scan(lambda.body);
1025                 } finally {
1026                     this.pt = prevPt;
1027                 }
1028             } else {
1029                 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
1030                     @Override
1031                     public void visitReturn(JCReturn tree) {
1032                         if (tree.expr != null) {
1033                             Type prevPt = CheckStuckPolicy.this.pt;
1034                             try {
1035                                 CheckStuckPolicy.this.pt = pt;
1036                                 CheckStuckPolicy.this.scan(tree.expr);
1037                             } finally {
1038                                 CheckStuckPolicy.this.pt = prevPt;
1039                             }
1040                         }
1041                     }
1042                 };
1043                 lambdaScanner.scan(lambda.body);
1044             }
1045         }
1046     }
1047 
1048     /**
1049      * This visitor is used to check that structural expressions conform
1050      * to their target - this step is required as inference could end up
1051      * inferring types that make some of the nested expressions incompatible
1052      * with their corresponding instantiated target
1053      */
1054     class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
1055 
1056         boolean stuck;
1057 
1058         @Override
1059         public boolean isStuck() {
1060             return super.isStuck() || stuck;
1061         }
1062 
1063         public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1064             super(resultInfo, dt);
1065         }
1066 
1067         @Override
1068         public void visitLambda(JCLambda tree) {
1069             super.visitLambda(tree);
1070             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
1071                 stuck = true;
1072             }
1073         }
1074 
1075         @Override
1076         public void visitReference(JCMemberReference tree) {
1077             super.visitReference(tree);
1078             if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1079                 stuck = true;
1080             }
1081         }
1082     }
1083 
1084     /**
1085      * Does the argument expression {@code expr} need speculative type-checking?
1086      */
1087     boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
1088         DeferredChecker dc = new DeferredChecker(env);
1089         dc.scan(expr);
1090         return dc.result.isPoly();
1091     }
1092 
1093     /**
1094      * The kind of an argument expression. This is used by the analysis that
1095      * determines as to whether speculative attribution is necessary.
1096      */
1097     enum ArgumentExpressionKind {
1098 
1099         /** kind that denotes poly argument expression */
1100         POLY,
1101         /** kind that denotes a standalone expression */
1102         NO_POLY,
1103         /** kind that denotes a primitive/boxed standalone expression */
1104         PRIMITIVE;
1105 
1106         /**
1107          * Does this kind denote a poly argument expression
1108          */
1109         public final boolean isPoly() {
1110             return this == POLY;
1111         }
1112 
1113         /**
1114          * Does this kind denote a primitive standalone expression
1115          */
1116         public final boolean isPrimitive() {
1117             return this == PRIMITIVE;
1118         }
1119 
1120         /**
1121          * Compute the kind of a standalone expression of a given type
1122          */
1123         static ArgumentExpressionKind standaloneKind(Type type, Types types) {
1124             return types.unboxedTypeOrType(type).isPrimitive() ?
1125                     ArgumentExpressionKind.PRIMITIVE :
1126                     ArgumentExpressionKind.NO_POLY;
1127         }
1128 
1129         /**
1130          * Compute the kind of a method argument expression given its symbol
1131          */
1132         static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
1133             Type restype = sym.type.getReturnType();
1134             if (sym.type.hasTag(FORALL) &&
1135                     restype.containsAny(((ForAll)sym.type).tvars)) {
1136                 return ArgumentExpressionKind.POLY;
1137             } else {
1138                 return ArgumentExpressionKind.standaloneKind(restype, types);
1139             }
1140         }
1141     }
1142 
1143     /**
1144      * Tree scanner used for checking as to whether an argument expression
1145      * requires speculative attribution
1146      */
1147     final class DeferredChecker extends FilterScanner {
1148 
1149         Env<AttrContext> env;
1150         ArgumentExpressionKind result;
1151 
1152         public DeferredChecker(Env<AttrContext> env) {
1153             super(deferredCheckerTags);
1154             this.env = env;
1155         }
1156 
1157         @Override
1158         public void visitLambda(JCLambda tree) {
1159             //a lambda is always a poly expression
1160             result = ArgumentExpressionKind.POLY;
1161         }
1162 
1163         @Override
1164         public void visitReference(JCMemberReference tree) {
1165             //perform arity-based check
1166             Env<AttrContext> localEnv = env.dup(tree);
1167             JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
1168                     attr.memberReferenceQualifierResult(tree));
1169             JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
1170             mref2.expr = exprTree;
1171             Symbol res =
1172                     rs.getMemberReference(tree, localEnv, mref2,
1173                         exprTree.type, tree.name);
1174             tree.sym = res;
1175             if (res.kind >= Kinds.ERRONEOUS ||
1176                     res.type.hasTag(FORALL) ||
1177                     (res.flags() & Flags.VARARGS) != 0 ||
1178                     (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
1179                     exprTree.type.isRaw())) {
1180                 tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
1181             } else {
1182                 tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
1183             }
1184             //a method reference is always a poly expression
1185             result = ArgumentExpressionKind.POLY;
1186         }
1187 
1188         @Override
1189         public void visitTypeCast(JCTypeCast tree) {
1190             //a cast is always a standalone expression
1191             result = ArgumentExpressionKind.NO_POLY;
1192         }
1193 
1194         @Override
1195         public void visitConditional(JCConditional tree) {
1196             scan(tree.truepart);
1197             if (!result.isPrimitive()) {
1198                 result = ArgumentExpressionKind.POLY;
1199                 return;
1200             }
1201             scan(tree.falsepart);
1202             result = reduce(ArgumentExpressionKind.PRIMITIVE);
1203         }
1204 
1205         @Override
1206         public void visitNewClass(JCNewClass tree) {
1207             result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
1208                     ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
1209         }
1210 
1211         @Override
1212         public void visitApply(JCMethodInvocation tree) {
1213             Name name = TreeInfo.name(tree.meth);
1214 
1215             //fast path
1216             if (tree.typeargs.nonEmpty() ||
1217                     name == name.table.names._this ||
1218                     name == name.table.names._super) {
1219                 result = ArgumentExpressionKind.NO_POLY;
1220                 return;
1221             }
1222 
1223             //slow path
1224             final JCExpression rec = tree.meth.hasTag(SELECT) ?
1225                     ((JCFieldAccess)tree.meth).selected :
1226                     null;
1227 
1228             if (rec != null && !isSimpleReceiver(rec)) {
1229                 //give up if receiver is too complex (to cut down analysis time)
1230                 result = ArgumentExpressionKind.POLY;
1231                 return;
1232             }
1233 
1234             Type site = rec != null ?
1235                     attribSpeculative(rec, env, attr.unknownTypeExprInfo).type :
1236                     env.enclClass.sym.type;
1237 
1238             while (site.hasTag(TYPEVAR)) {
1239                 site = site.getUpperBound();
1240             }
1241 
1242             List<Type> args = rs.dummyArgs(tree.args.length());
1243 
1244             Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
1245                 @Override
1246                 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
1247                     return rec == null ?
1248                         rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
1249                         rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
1250                 }
1251                 @Override
1252                 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
1253                     return sym;
1254                 }
1255             };
1256 
1257             Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
1258 
1259             if (sym.kind == Kinds.AMBIGUOUS) {
1260                 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
1261                 result = ArgumentExpressionKind.PRIMITIVE;
1262                 for (Symbol s : err.ambiguousSyms) {
1263                     if (result.isPoly()) break;
1264                     if (s.kind == Kinds.MTH) {
1265                         result = reduce(ArgumentExpressionKind.methodKind(s, types));
1266                     }
1267                 }
1268             } else {
1269                 result = (sym.kind == Kinds.MTH) ?
1270                     ArgumentExpressionKind.methodKind(sym, types) :
1271                     ArgumentExpressionKind.NO_POLY;
1272             }
1273         }
1274         //where
1275             private boolean isSimpleReceiver(JCTree rec) {
1276                 switch (rec.getTag()) {
1277                     case IDENT:
1278                         return true;
1279                     case SELECT:
1280                         return isSimpleReceiver(((JCFieldAccess)rec).selected);
1281                     case TYPEAPPLY:
1282                     case TYPEARRAY:
1283                         return true;
1284                     case ANNOTATED_TYPE:
1285                         return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
1286                     default:
1287                         return false;
1288                 }
1289             }
1290             private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
1291                 switch (result) {
1292                     case PRIMITIVE: return kind;
1293                     case NO_POLY: return kind.isPoly() ? kind : result;
1294                     case POLY: return result;
1295                     default:
1296                         Assert.error();
1297                         return null;
1298                 }
1299             }
1300 
1301         @Override
1302         public void visitLiteral(JCLiteral tree) {
1303             Type litType = attr.litType(tree.typetag);
1304             result = ArgumentExpressionKind.standaloneKind(litType, types);
1305         }
1306 
1307         @Override
1308         void skip(JCTree tree) {
1309             result = ArgumentExpressionKind.NO_POLY;
1310         }
1311     }
1312     //where
1313     private EnumSet<JCTree.Tag> deferredCheckerTags =
1314             EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
1315                     CONDEXPR, NEWCLASS, APPLY, LITERAL);
1316 }