src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java

Mon, 16 Oct 2017 16:07:48 +0800

author
aoqi
date
Mon, 16 Oct 2017 16:07:48 +0800
changeset 2893
ca5783d9a597
parent 2811
610ec7dcf431
parent 2702
9ca8d8713094
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 2012, 2015, 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  */
    26 package com.sun.tools.javac.comp;
    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.*;
    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;
    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.*;
    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 =
    66         new Context.Key<DeferredAttr>();
    68     final Attr attr;
    69     final Check chk;
    70     final JCDiagnostic.Factory diags;
    71     final Enter enter;
    72     final Infer infer;
    73     final Resolve rs;
    74     final Log log;
    75     final Symtab syms;
    76     final TreeMaker make;
    77     final Types types;
    78     final Flow flow;
    79     final Names names;
    80     final TypeEnvs typeEnvs;
    82     public static DeferredAttr instance(Context context) {
    83         DeferredAttr instance = context.get(deferredAttrKey);
    84         if (instance == null)
    85             instance = new DeferredAttr(context);
    86         return instance;
    87     }
    89     protected DeferredAttr(Context context) {
    90         context.put(deferredAttrKey, this);
    91         attr = Attr.instance(context);
    92         chk = Check.instance(context);
    93         diags = JCDiagnostic.Factory.instance(context);
    94         enter = Enter.instance(context);
    95         infer = Infer.instance(context);
    96         rs = Resolve.instance(context);
    97         log = Log.instance(context);
    98         syms = Symtab.instance(context);
    99         make = TreeMaker.instance(context);
   100         types = Types.instance(context);
   101         flow = Flow.instance(context);
   102         names = Names.instance(context);
   103         stuckTree = make.Ident(names.empty).setType(Type.stuckType);
   104         typeEnvs = TypeEnvs.instance(context);
   105         emptyDeferredAttrContext =
   106             new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) {
   107                 @Override
   108                 void addDeferredAttrNode(DeferredType dt, ResultInfo ri, DeferredStuckPolicy deferredStuckPolicy) {
   109                     Assert.error("Empty deferred context!");
   110                 }
   111                 @Override
   112                 void complete() {
   113                     Assert.error("Empty deferred context!");
   114                 }
   116                 @Override
   117                 public String toString() {
   118                     return "Empty deferred context!";
   119                 }
   120             };
   121     }
   123     /** shared tree for stuck expressions */
   124     final JCTree stuckTree;
   126     /**
   127      * This type represents a deferred type. A deferred type starts off with
   128      * no information on the underlying expression type. Such info needs to be
   129      * discovered through type-checking the deferred type against a target-type.
   130      * Every deferred type keeps a pointer to the AST node from which it originated.
   131      */
   132     public class DeferredType extends Type {
   134         public JCExpression tree;
   135         Env<AttrContext> env;
   136         AttrMode mode;
   137         SpeculativeCache speculativeCache;
   139         DeferredType(JCExpression tree, Env<AttrContext> env) {
   140             super(null);
   141             this.tree = tree;
   142             this.env = attr.copyEnv(env);
   143             this.speculativeCache = new SpeculativeCache();
   144         }
   146         @Override
   147         public TypeTag getTag() {
   148             return DEFERRED;
   149         }
   151         @Override
   152         public String toString() {
   153             return "DeferredType";
   154         }
   156         /**
   157          * A speculative cache is used to keep track of all overload resolution rounds
   158          * that triggered speculative attribution on a given deferred type. Each entry
   159          * stores a pointer to the speculative tree and the resolution phase in which the entry
   160          * has been added.
   161          */
   162         class SpeculativeCache {
   164             private Map<Symbol, List<Entry>> cache =
   165                     new WeakHashMap<Symbol, List<Entry>>();
   167             class Entry {
   168                 JCTree speculativeTree;
   169                 ResultInfo resultInfo;
   171                 public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
   172                     this.speculativeTree = speculativeTree;
   173                     this.resultInfo = resultInfo;
   174                 }
   176                 boolean matches(MethodResolutionPhase phase) {
   177                     return resultInfo.checkContext.deferredAttrContext().phase == phase;
   178                 }
   179             }
   181             /**
   182              * Retrieve a speculative cache entry corresponding to given symbol
   183              * and resolution phase
   184              */
   185             Entry get(Symbol msym, MethodResolutionPhase phase) {
   186                 List<Entry> entries = cache.get(msym);
   187                 if (entries == null) return null;
   188                 for (Entry e : entries) {
   189                     if (e.matches(phase)) return e;
   190                 }
   191                 return null;
   192             }
   194             /**
   195              * Stores a speculative cache entry corresponding to given symbol
   196              * and resolution phase
   197              */
   198             void put(JCTree speculativeTree, ResultInfo resultInfo) {
   199                 Symbol msym = resultInfo.checkContext.deferredAttrContext().msym;
   200                 List<Entry> entries = cache.get(msym);
   201                 if (entries == null) {
   202                     entries = List.nil();
   203                 }
   204                 cache.put(msym, entries.prepend(new Entry(speculativeTree, resultInfo)));
   205             }
   206         }
   208         /**
   209          * Get the type that has been computed during a speculative attribution round
   210          */
   211         Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
   212             SpeculativeCache.Entry e = speculativeCache.get(msym, phase);
   213             return e != null ? e.speculativeTree.type : Type.noType;
   214         }
   216         /**
   217          * Check a deferred type against a potential target-type. Depending on
   218          * the current attribution mode, a normal vs. speculative attribution
   219          * round is performed on the underlying AST node. There can be only one
   220          * speculative round for a given target method symbol; moreover, a normal
   221          * attribution round must follow one or more speculative rounds.
   222          */
   223         Type check(ResultInfo resultInfo) {
   224             DeferredStuckPolicy deferredStuckPolicy;
   225             if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) {
   226                 deferredStuckPolicy = dummyStuckPolicy;
   227             } else if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.SPECULATIVE ||
   228                     resultInfo.checkContext.deferredAttrContext().insideOverloadPhase()) {
   229                 deferredStuckPolicy = new OverloadStuckPolicy(resultInfo, this);
   230             } else {
   231                 deferredStuckPolicy = new CheckStuckPolicy(resultInfo, this);
   232             }
   233             return check(resultInfo, deferredStuckPolicy, basicCompleter);
   234         }
   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     }
   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     }
   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     };
   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     };
   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     }
   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     };
   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     }
   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<Object>(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;
   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();
   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                 typeEnvs.remove(csym);
   407                 chk.compiled.remove(csym.flatname);
   408                 syms.classes.remove(csym.flatname);
   409                 super.visitClassDef(tree);
   410             }
   411         }
   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 {
   426         /** attribution mode */
   427         final AttrMode mode;
   429         /** symbol of the method being checked */
   430         final Symbol msym;
   432         /** method resolution step */
   433         final Resolve.MethodResolutionPhase phase;
   435         /** inference context */
   436         final InferenceContext inferenceContext;
   438         /** parent deferred context */
   439         final DeferredAttrContext parent;
   441         /** Warner object to report warnings */
   442         final Warner warn;
   444         /** list of deferred attribution nodes to be processed */
   445         ArrayList<DeferredAttrNode> deferredAttrNodes = new ArrayList<DeferredAttrNode>();
   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         }
   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         }
   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<Type, Set<Type>>();
   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<Type>();
   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                     if (insideOverloadPhase()) {
   502                         for (DeferredAttrNode deferredNode: deferredAttrNodes) {
   503                             deferredNode.dt.tree.type = Type.noType;
   504                         }
   505                         return;
   506                     }
   507                     //remove all variables that have already been instantiated
   508                     //from the list of stuck variables
   509                     try {
   510                         inferenceContext.solveAny(stuckVars, depVarsMap, warn);
   511                         inferenceContext.notifyChange();
   512                     } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
   513                         //this means that we are in speculative mode and the
   514                         //set of contraints are too tight for progess to be made.
   515                         //Just leave the remaining expressions as stuck.
   516                         break;
   517                     }
   518                 }
   519             }
   520         }
   522         private boolean insideOverloadPhase() {
   523             DeferredAttrContext dac = this;
   524             if (dac == emptyDeferredAttrContext) {
   525                 return false;
   526             }
   527             if (dac.mode == AttrMode.SPECULATIVE) {
   528                 return true;
   529             }
   530             return dac.parent.insideOverloadPhase();
   531         }
   532     }
   534     /**
   535      * Class representing a deferred attribution node. It keeps track of
   536      * a deferred type, along with the expected target type information.
   537      */
   538     class DeferredAttrNode {
   540         /** underlying deferred type */
   541         DeferredType dt;
   543         /** underlying target type information */
   544         ResultInfo resultInfo;
   546         /** stuck policy associated with this node */
   547         DeferredStuckPolicy deferredStuckPolicy;
   549         DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
   550             this.dt = dt;
   551             this.resultInfo = resultInfo;
   552             this.deferredStuckPolicy = deferredStuckPolicy;
   553         }
   555         /**
   556          * Process a deferred attribution node.
   557          * Invariant: a stuck node cannot be processed.
   558          */
   559         @SuppressWarnings("fallthrough")
   560         boolean process(final DeferredAttrContext deferredAttrContext) {
   561             switch (deferredAttrContext.mode) {
   562                 case SPECULATIVE:
   563                     if (deferredStuckPolicy.isStuck()) {
   564                         dt.check(resultInfo, dummyStuckPolicy, new StructuralStuckChecker());
   565                         return true;
   566                     } else {
   567                         Assert.error("Cannot get here");
   568                     }
   569                 case CHECK:
   570                     if (deferredStuckPolicy.isStuck()) {
   571                         //stuck expression - see if we can propagate
   572                         if (deferredAttrContext.parent != emptyDeferredAttrContext &&
   573                                 Type.containsAny(deferredAttrContext.parent.inferenceContext.inferencevars,
   574                                         List.from(deferredStuckPolicy.stuckVars()))) {
   575                             deferredAttrContext.parent.addDeferredAttrNode(dt,
   576                                     resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) {
   577                                 @Override
   578                                 public InferenceContext inferenceContext() {
   579                                     return deferredAttrContext.parent.inferenceContext;
   580                                 }
   581                                 @Override
   582                                 public DeferredAttrContext deferredAttrContext() {
   583                                     return deferredAttrContext.parent;
   584                                 }
   585                             }), deferredStuckPolicy);
   586                             dt.tree.type = Type.stuckType;
   587                             return true;
   588                         } else {
   589                             return false;
   590                         }
   591                     } else {
   592                         Assert.check(!deferredAttrContext.insideOverloadPhase(),
   593                                 "attribution shouldn't be happening here");
   594                         ResultInfo instResultInfo =
   595                                 resultInfo.dup(deferredAttrContext.inferenceContext.asInstType(resultInfo.pt));
   596                         dt.check(instResultInfo, dummyStuckPolicy, basicCompleter);
   597                         return true;
   598                     }
   599                 default:
   600                     throw new AssertionError("Bad mode");
   601             }
   602         }
   604         /**
   605          * Structural checker for stuck expressions
   606          */
   607         class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
   609             ResultInfo resultInfo;
   610             InferenceContext inferenceContext;
   611             Env<AttrContext> env;
   613             public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
   614                 this.resultInfo = resultInfo;
   615                 this.inferenceContext = deferredAttrContext.inferenceContext;
   616                 this.env = dt.env;
   617                 dt.tree.accept(this);
   618                 dt.speculativeCache.put(stuckTree, resultInfo);
   619                 return Type.noType;
   620             }
   622             @Override
   623             public void visitLambda(JCLambda tree) {
   624                 Check.CheckContext checkContext = resultInfo.checkContext;
   625                 Type pt = resultInfo.pt;
   626                 if (!inferenceContext.inferencevars.contains(pt)) {
   627                     //must be a functional descriptor
   628                     Type descriptorType = null;
   629                     try {
   630                         descriptorType = types.findDescriptorType(pt);
   631                     } catch (Types.FunctionDescriptorLookupError ex) {
   632                         checkContext.report(null, ex.getDiagnostic());
   633                     }
   635                     if (descriptorType.getParameterTypes().length() != tree.params.length()) {
   636                         checkContext.report(tree,
   637                                 diags.fragment("incompatible.arg.types.in.lambda"));
   638                     }
   640                     Type currentReturnType = descriptorType.getReturnType();
   641                     boolean returnTypeIsVoid = currentReturnType.hasTag(VOID);
   642                     if (tree.getBodyKind() == BodyKind.EXPRESSION) {
   643                         boolean isExpressionCompatible = !returnTypeIsVoid ||
   644                             TreeInfo.isExpressionStatement((JCExpression)tree.getBody());
   645                         if (!isExpressionCompatible) {
   646                             resultInfo.checkContext.report(tree.pos(),
   647                                 diags.fragment("incompatible.ret.type.in.lambda",
   648                                     diags.fragment("missing.ret.val", currentReturnType)));
   649                         }
   650                     } else {
   651                         LambdaBodyStructChecker lambdaBodyChecker =
   652                                 new LambdaBodyStructChecker();
   654                         tree.body.accept(lambdaBodyChecker);
   655                         boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
   657                         if (returnTypeIsVoid) {
   658                             if (!isVoidCompatible) {
   659                                 resultInfo.checkContext.report(tree.pos(),
   660                                     diags.fragment("unexpected.ret.val"));
   661                             }
   662                         } else {
   663                             boolean isValueCompatible = lambdaBodyChecker.isPotentiallyValueCompatible
   664                                 && !canLambdaBodyCompleteNormally(tree);
   665                             if (!isValueCompatible && !isVoidCompatible) {
   666                                 log.error(tree.body.pos(),
   667                                     "lambda.body.neither.value.nor.void.compatible");
   668                             }
   670                             if (!isValueCompatible) {
   671                                 resultInfo.checkContext.report(tree.pos(),
   672                                     diags.fragment("incompatible.ret.type.in.lambda",
   673                                         diags.fragment("missing.ret.val", currentReturnType)));
   674                             }
   675                         }
   676                     }
   677                 }
   678             }
   680             boolean canLambdaBodyCompleteNormally(JCLambda tree) {
   681                 JCLambda newTree = new TreeCopier<>(make).copy(tree);
   682                 /* attr.lambdaEnv will create a meaningful env for the
   683                  * lambda expression. This is specially useful when the
   684                  * lambda is used as the init of a field. But we need to
   685                  * remove any added symbol.
   686                  */
   687                 Env<AttrContext> localEnv = attr.lambdaEnv(newTree, env);
   688                 try {
   689                     List<JCVariableDecl> tmpParams = newTree.params;
   690                     while (tmpParams.nonEmpty()) {
   691                         tmpParams.head.vartype = make.at(tmpParams.head).Type(syms.errType);
   692                         tmpParams = tmpParams.tail;
   693                     }
   695                     attr.attribStats(newTree.params, localEnv);
   697                     /* set pt to Type.noType to avoid generating any bound
   698                      * which may happen if lambda's return type is an
   699                      * inference variable
   700                      */
   701                     Attr.ResultInfo bodyResultInfo = attr.new ResultInfo(VAL, Type.noType);
   702                     localEnv.info.returnResult = bodyResultInfo;
   704                     // discard any log output
   705                     Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
   706                     try {
   707                         JCBlock body = (JCBlock)newTree.body;
   708                         /* we need to attribute the lambda body before
   709                          * doing the aliveness analysis. This is because
   710                          * constant folding occurs during attribution
   711                          * and the reachability of some statements depends
   712                          * on constant values, for example:
   713                          *
   714                          *     while (true) {...}
   715                          */
   716                         attr.attribStats(body.stats, localEnv);
   718                         attr.preFlow(newTree);
   719                         /* make an aliveness / reachability analysis of the lambda
   720                          * to determine if it can complete normally
   721                          */
   722                         flow.analyzeLambda(localEnv, newTree, make, true);
   723                     } finally {
   724                         log.popDiagnosticHandler(diagHandler);
   725                     }
   726                     return newTree.canCompleteNormally;
   727                 } finally {
   728                     JCBlock body = (JCBlock)newTree.body;
   729                     unenterScanner.scan(body.stats);
   730                     localEnv.info.scope.leave();
   731                 }
   732             }
   734             @Override
   735             public void visitNewClass(JCNewClass tree) {
   736                 //do nothing
   737             }
   739             @Override
   740             public void visitApply(JCMethodInvocation tree) {
   741                 //do nothing
   742             }
   744             @Override
   745             public void visitReference(JCMemberReference tree) {
   746                 Check.CheckContext checkContext = resultInfo.checkContext;
   747                 Type pt = resultInfo.pt;
   748                 if (!inferenceContext.inferencevars.contains(pt)) {
   749                     try {
   750                         types.findDescriptorType(pt);
   751                     } catch (Types.FunctionDescriptorLookupError ex) {
   752                         checkContext.report(null, ex.getDiagnostic());
   753                     }
   754                     Env<AttrContext> localEnv = env.dup(tree);
   755                     JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
   756                             attr.memberReferenceQualifierResult(tree));
   757                     ListBuffer<Type> argtypes = new ListBuffer<>();
   758                     for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
   759                         argtypes.append(Type.noType);
   760                     }
   761                     JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
   762                     mref2.expr = exprTree;
   763                     Symbol lookupSym =
   764                             rs.resolveMemberReferenceByArity(localEnv, mref2, exprTree.type,
   765                                 tree.name, argtypes.toList(), inferenceContext);
   766                     switch (lookupSym.kind) {
   767                         //note: as argtypes are erroneous types, type-errors must
   768                         //have been caused by arity mismatch
   769                         case Kinds.ABSENT_MTH:
   770                         case Kinds.WRONG_MTH:
   771                         case Kinds.WRONG_MTHS:
   772                         case Kinds.WRONG_STATICNESS:
   773                            checkContext.report(tree, diags.fragment("incompatible.arg.types.in.mref"));
   774                     }
   775                 }
   776             }
   777         }
   779         /* This visitor looks for return statements, its analysis will determine if
   780          * a lambda body is void or value compatible. We must analyze return
   781          * statements contained in the lambda body only, thus any return statement
   782          * contained in an inner class or inner lambda body, should be ignored.
   783          */
   784         class LambdaBodyStructChecker extends TreeScanner {
   785             boolean isVoidCompatible = true;
   786             boolean isPotentiallyValueCompatible = true;
   788             @Override
   789             public void visitClassDef(JCClassDecl tree) {
   790                 // do nothing
   791             }
   793             @Override
   794             public void visitLambda(JCLambda tree) {
   795                 // do nothing
   796             }
   798             @Override
   799             public void visitNewClass(JCNewClass tree) {
   800                 // do nothing
   801             }
   803             @Override
   804             public void visitReturn(JCReturn tree) {
   805                 if (tree.expr != null) {
   806                     isVoidCompatible = false;
   807                 } else {
   808                     isPotentiallyValueCompatible = false;
   809                 }
   810             }
   811         }
   812     }
   814     /** an empty deferred attribution context - all methods throw exceptions */
   815     final DeferredAttrContext emptyDeferredAttrContext;
   817     /**
   818      * Map a list of types possibly containing one or more deferred types
   819      * into a list of ordinary types. Each deferred type D is mapped into a type T,
   820      * where T is computed by retrieving the type that has already been
   821      * computed for D during a previous deferred attribution round of the given kind.
   822      */
   823     class DeferredTypeMap extends Type.Mapping {
   825         DeferredAttrContext deferredAttrContext;
   827         protected DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
   828             super(String.format("deferredTypeMap[%s]", mode));
   829             this.deferredAttrContext = new DeferredAttrContext(mode, msym, phase,
   830                     infer.emptyContext, emptyDeferredAttrContext, types.noWarnings);
   831         }
   833         @Override
   834         public Type apply(Type t) {
   835             if (!t.hasTag(DEFERRED)) {
   836                 return t.map(this);
   837             } else {
   838                 DeferredType dt = (DeferredType)t;
   839                 return typeOf(dt);
   840             }
   841         }
   843         protected Type typeOf(DeferredType dt) {
   844             switch (deferredAttrContext.mode) {
   845                 case CHECK:
   846                     return dt.tree.type == null ? Type.noType : dt.tree.type;
   847                 case SPECULATIVE:
   848                     return dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase);
   849             }
   850             Assert.error();
   851             return null;
   852         }
   853     }
   855     /**
   856      * Specialized recovery deferred mapping.
   857      * Each deferred type D is mapped into a type T, where T is computed either by
   858      * (i) retrieving the type that has already been computed for D during a previous
   859      * attribution round (as before), or (ii) by synthesizing a new type R for D
   860      * (the latter step is useful in a recovery scenario).
   861      */
   862     public class RecoveryDeferredTypeMap extends DeferredTypeMap {
   864         public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
   865             super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
   866         }
   868         @Override
   869         protected Type typeOf(DeferredType dt) {
   870             Type owntype = super.typeOf(dt);
   871             return owntype == Type.noType ?
   872                         recover(dt) : owntype;
   873         }
   875         /**
   876          * Synthesize a type for a deferred type that hasn't been previously
   877          * reduced to an ordinary type. Functional deferred types and conditionals
   878          * are mapped to themselves, in order to have a richer diagnostic
   879          * representation. Remaining deferred types are attributed using
   880          * a default expected type (j.l.Object).
   881          */
   882         private Type recover(DeferredType dt) {
   883             dt.check(attr.new RecoveryInfo(deferredAttrContext) {
   884                 @Override
   885                 protected Type check(DiagnosticPosition pos, Type found) {
   886                     return chk.checkNonVoid(pos, super.check(pos, found));
   887                 }
   888             });
   889             return super.apply(dt);
   890         }
   891     }
   893     /**
   894      * A special tree scanner that would only visit portions of a given tree.
   895      * The set of nodes visited by the scanner can be customized at construction-time.
   896      */
   897     abstract static class FilterScanner extends TreeScanner {
   899         final Filter<JCTree> treeFilter;
   901         FilterScanner(final Set<JCTree.Tag> validTags) {
   902             this.treeFilter = new Filter<JCTree>() {
   903                 public boolean accepts(JCTree t) {
   904                     return validTags.contains(t.getTag());
   905                 }
   906             };
   907         }
   909         @Override
   910         public void scan(JCTree tree) {
   911             if (tree != null) {
   912                 if (treeFilter.accepts(tree)) {
   913                     super.scan(tree);
   914                 } else {
   915                     skip(tree);
   916                 }
   917             }
   918         }
   920         /**
   921          * handler that is executed when a node has been discarded
   922          */
   923         void skip(JCTree tree) {}
   924     }
   926     /**
   927      * A tree scanner suitable for visiting the target-type dependent nodes of
   928      * a given argument expression.
   929      */
   930     static class PolyScanner extends FilterScanner {
   932         PolyScanner() {
   933             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
   934         }
   935     }
   937     /**
   938      * A tree scanner suitable for visiting the target-type dependent nodes nested
   939      * within a lambda expression body.
   940      */
   941     static class LambdaReturnScanner extends FilterScanner {
   943         LambdaReturnScanner() {
   944             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
   945                     FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
   946         }
   947     }
   949     /**
   950      * This visitor is used to check that structural expressions conform
   951      * to their target - this step is required as inference could end up
   952      * inferring types that make some of the nested expressions incompatible
   953      * with their corresponding instantiated target
   954      */
   955     class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener {
   957         Type pt;
   958         Infer.InferenceContext inferenceContext;
   959         Set<Type> stuckVars = new LinkedHashSet<Type>();
   960         Set<Type> depVars = new LinkedHashSet<Type>();
   962         @Override
   963         public boolean isStuck() {
   964             return !stuckVars.isEmpty();
   965         }
   967         @Override
   968         public Set<Type> stuckVars() {
   969             return stuckVars;
   970         }
   972         @Override
   973         public Set<Type> depVars() {
   974             return depVars;
   975         }
   977         public CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
   978             this.pt = resultInfo.pt;
   979             this.inferenceContext = resultInfo.checkContext.inferenceContext();
   980             scan(dt.tree);
   981             if (!stuckVars.isEmpty()) {
   982                 resultInfo.checkContext.inferenceContext()
   983                         .addFreeTypeListener(List.from(stuckVars), this);
   984             }
   985         }
   987         @Override
   988         public void typesInferred(InferenceContext inferenceContext) {
   989             stuckVars.clear();
   990         }
   992         @Override
   993         public void visitLambda(JCLambda tree) {
   994             if (inferenceContext.inferenceVars().contains(pt)) {
   995                 stuckVars.add(pt);
   996             }
   997             if (!types.isFunctionalInterface(pt)) {
   998                 return;
   999             }
  1000             Type descType = types.findDescriptorType(pt);
  1001             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
  1002             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT &&
  1003                     freeArgVars.nonEmpty()) {
  1004                 stuckVars.addAll(freeArgVars);
  1005                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
  1007             scanLambdaBody(tree, descType.getReturnType());
  1010         @Override
  1011         public void visitReference(JCMemberReference tree) {
  1012             scan(tree.expr);
  1013             if (inferenceContext.inferenceVars().contains(pt)) {
  1014                 stuckVars.add(pt);
  1015                 return;
  1017             if (!types.isFunctionalInterface(pt)) {
  1018                 return;
  1021             Type descType = types.findDescriptorType(pt);
  1022             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
  1023             if (freeArgVars.nonEmpty() &&
  1024                     tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
  1025                 stuckVars.addAll(freeArgVars);
  1026                 depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
  1030         void scanLambdaBody(JCLambda lambda, final Type pt) {
  1031             if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
  1032                 Type prevPt = this.pt;
  1033                 try {
  1034                     this.pt = pt;
  1035                     scan(lambda.body);
  1036                 } finally {
  1037                     this.pt = prevPt;
  1039             } else {
  1040                 LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() {
  1041                     @Override
  1042                     public void visitReturn(JCReturn tree) {
  1043                         if (tree.expr != null) {
  1044                             Type prevPt = CheckStuckPolicy.this.pt;
  1045                             try {
  1046                                 CheckStuckPolicy.this.pt = pt;
  1047                                 CheckStuckPolicy.this.scan(tree.expr);
  1048                             } finally {
  1049                                 CheckStuckPolicy.this.pt = prevPt;
  1053                 };
  1054                 lambdaScanner.scan(lambda.body);
  1059     /**
  1060      * This visitor is used to check that structural expressions conform
  1061      * to their target - this step is required as inference could end up
  1062      * inferring types that make some of the nested expressions incompatible
  1063      * with their corresponding instantiated target
  1064      */
  1065     class OverloadStuckPolicy extends CheckStuckPolicy implements DeferredStuckPolicy {
  1067         boolean stuck;
  1069         @Override
  1070         public boolean isStuck() {
  1071             return super.isStuck() || stuck;
  1074         public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
  1075             super(resultInfo, dt);
  1078         @Override
  1079         public void visitLambda(JCLambda tree) {
  1080             super.visitLambda(tree);
  1081             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
  1082                 stuck = true;
  1086         @Override
  1087         public void visitReference(JCMemberReference tree) {
  1088             super.visitReference(tree);
  1089             if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
  1090                 stuck = true;
  1095     /**
  1096      * Does the argument expression {@code expr} need speculative type-checking?
  1097      */
  1098     boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
  1099         DeferredChecker dc = new DeferredChecker(env);
  1100         dc.scan(expr);
  1101         return dc.result.isPoly();
  1104     /**
  1105      * The kind of an argument expression. This is used by the analysis that
  1106      * determines as to whether speculative attribution is necessary.
  1107      */
  1108     enum ArgumentExpressionKind {
  1110         /** kind that denotes poly argument expression */
  1111         POLY,
  1112         /** kind that denotes a standalone expression */
  1113         NO_POLY,
  1114         /** kind that denotes a primitive/boxed standalone expression */
  1115         PRIMITIVE;
  1117         /**
  1118          * Does this kind denote a poly argument expression
  1119          */
  1120         public final boolean isPoly() {
  1121             return this == POLY;
  1124         /**
  1125          * Does this kind denote a primitive standalone expression
  1126          */
  1127         public final boolean isPrimitive() {
  1128             return this == PRIMITIVE;
  1131         /**
  1132          * Compute the kind of a standalone expression of a given type
  1133          */
  1134         static ArgumentExpressionKind standaloneKind(Type type, Types types) {
  1135             return types.unboxedTypeOrType(type).isPrimitive() ?
  1136                     ArgumentExpressionKind.PRIMITIVE :
  1137                     ArgumentExpressionKind.NO_POLY;
  1140         /**
  1141          * Compute the kind of a method argument expression given its symbol
  1142          */
  1143         static ArgumentExpressionKind methodKind(Symbol sym, Types types) {
  1144             Type restype = sym.type.getReturnType();
  1145             if (sym.type.hasTag(FORALL) &&
  1146                     restype.containsAny(((ForAll)sym.type).tvars)) {
  1147                 return ArgumentExpressionKind.POLY;
  1148             } else {
  1149                 return ArgumentExpressionKind.standaloneKind(restype, types);
  1154     /**
  1155      * Tree scanner used for checking as to whether an argument expression
  1156      * requires speculative attribution
  1157      */
  1158     final class DeferredChecker extends FilterScanner {
  1160         Env<AttrContext> env;
  1161         ArgumentExpressionKind result;
  1163         public DeferredChecker(Env<AttrContext> env) {
  1164             super(deferredCheckerTags);
  1165             this.env = env;
  1168         @Override
  1169         public void visitLambda(JCLambda tree) {
  1170             //a lambda is always a poly expression
  1171             result = ArgumentExpressionKind.POLY;
  1174         @Override
  1175         public void visitReference(JCMemberReference tree) {
  1176             //perform arity-based check
  1177             Env<AttrContext> localEnv = env.dup(tree);
  1178             JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
  1179                     attr.memberReferenceQualifierResult(tree));
  1180             JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
  1181             mref2.expr = exprTree;
  1182             Symbol res =
  1183                     rs.getMemberReference(tree, localEnv, mref2,
  1184                         exprTree.type, tree.name);
  1185             tree.sym = res;
  1186             if (res.kind >= Kinds.ERRONEOUS ||
  1187                     res.type.hasTag(FORALL) ||
  1188                     (res.flags() & Flags.VARARGS) != 0 ||
  1189                     (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
  1190                     exprTree.type.isRaw())) {
  1191                 tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
  1192             } else {
  1193                 tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
  1195             //a method reference is always a poly expression
  1196             result = ArgumentExpressionKind.POLY;
  1199         @Override
  1200         public void visitTypeCast(JCTypeCast tree) {
  1201             //a cast is always a standalone expression
  1202             result = ArgumentExpressionKind.NO_POLY;
  1205         @Override
  1206         public void visitConditional(JCConditional tree) {
  1207             scan(tree.truepart);
  1208             if (!result.isPrimitive()) {
  1209                 result = ArgumentExpressionKind.POLY;
  1210                 return;
  1212             scan(tree.falsepart);
  1213             result = reduce(ArgumentExpressionKind.PRIMITIVE);
  1216         @Override
  1217         public void visitNewClass(JCNewClass tree) {
  1218             result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
  1219                     ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
  1222         @Override
  1223         public void visitApply(JCMethodInvocation tree) {
  1224             Name name = TreeInfo.name(tree.meth);
  1226             //fast path
  1227             if (tree.typeargs.nonEmpty() ||
  1228                     name == name.table.names._this ||
  1229                     name == name.table.names._super) {
  1230                 result = ArgumentExpressionKind.NO_POLY;
  1231                 return;
  1234             //slow path
  1235             Symbol sym = quicklyResolveMethod(env, tree);
  1237             if (sym == null) {
  1238                 result = ArgumentExpressionKind.POLY;
  1239                 return;
  1242             result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
  1243                     argumentKindAnalyzer);
  1245         //where
  1246             private boolean isSimpleReceiver(JCTree rec) {
  1247                 switch (rec.getTag()) {
  1248                     case IDENT:
  1249                         return true;
  1250                     case SELECT:
  1251                         return isSimpleReceiver(((JCFieldAccess)rec).selected);
  1252                     case TYPEAPPLY:
  1253                     case TYPEARRAY:
  1254                         return true;
  1255                     case ANNOTATED_TYPE:
  1256                         return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
  1257                     case APPLY:
  1258                         return true;
  1259                     case NEWCLASS:
  1260                         JCNewClass nc = (JCNewClass) rec;
  1261                         return nc.encl == null && nc.def == null && !TreeInfo.isDiamond(nc);
  1262                     default:
  1263                         return false;
  1266             private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
  1267                 return argumentKindAnalyzer.reduce(result, kind);
  1269             MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
  1270                     new MethodAnalyzer<ArgumentExpressionKind>() {
  1271                 @Override
  1272                 public ArgumentExpressionKind process(MethodSymbol ms) {
  1273                     return ArgumentExpressionKind.methodKind(ms, types);
  1275                 @Override
  1276                 public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1,
  1277                                                      ArgumentExpressionKind kind2) {
  1278                     switch (kind1) {
  1279                         case PRIMITIVE: return kind2;
  1280                         case NO_POLY: return kind2.isPoly() ? kind2 : kind1;
  1281                         case POLY: return kind1;
  1282                         default:
  1283                             Assert.error();
  1284                             return null;
  1287                 @Override
  1288                 public boolean shouldStop(ArgumentExpressionKind result) {
  1289                     return result.isPoly();
  1291             };
  1293         @Override
  1294         public void visitLiteral(JCLiteral tree) {
  1295             Type litType = attr.litType(tree.typetag);
  1296             result = ArgumentExpressionKind.standaloneKind(litType, types);
  1299         @Override
  1300         void skip(JCTree tree) {
  1301             result = ArgumentExpressionKind.NO_POLY;
  1304         private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) {
  1305             final JCExpression rec = tree.meth.hasTag(SELECT) ?
  1306                     ((JCFieldAccess)tree.meth).selected :
  1307                     null;
  1309             if (rec != null && !isSimpleReceiver(rec)) {
  1310                 return null;
  1313             Type site;
  1315             if (rec != null) {
  1316                 switch (rec.getTag()) {
  1317                     case APPLY:
  1318                         Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec);
  1319                         if (recSym == null)
  1320                             return null;
  1321                         Symbol resolvedReturnType =
  1322                                 analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer);
  1323                         if (resolvedReturnType == null)
  1324                             return null;
  1325                         site = resolvedReturnType.type;
  1326                         break;
  1327                     case NEWCLASS:
  1328                         JCNewClass nc = (JCNewClass) rec;
  1329                         site = attribSpeculative(nc.clazz, env, attr.unknownTypeExprInfo).type;
  1330                         break;
  1331                     default:
  1332                         site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type;
  1333                         break;
  1335             } else {
  1336                 site = env.enclClass.sym.type;
  1339             while (site.hasTag(TYPEVAR)) {
  1340                 site = site.getUpperBound();
  1343             site = types.capture(site);
  1345             List<Type> args = rs.dummyArgs(tree.args.length());
  1346             Name name = TreeInfo.name(tree.meth);
  1348             Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
  1349                 @Override
  1350                 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
  1351                     return rec == null ?
  1352                         rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
  1353                         rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false);
  1355                 @Override
  1356                 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
  1357                     return sym;
  1359             };
  1361             return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
  1363         //where:
  1364             MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() {
  1365                 @Override
  1366                 public Symbol process(MethodSymbol ms) {
  1367                     ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types);
  1368                     if (kind == ArgumentExpressionKind.POLY || ms.getReturnType().hasTag(TYPEVAR))
  1369                         return null;
  1370                     return ms.getReturnType().tsym;
  1372                 @Override
  1373                 public Symbol reduce(Symbol s1, Symbol s2) {
  1374                     return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
  1376                 @Override
  1377                 public boolean shouldStop(Symbol result) {
  1378                     return result == null;
  1380             };
  1382         /**
  1383          * Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of
  1384          * MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate
  1385          * methods are inspected one by one, using MethodAnalyzer.process. The outcomes are
  1386          * reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which
  1387          * the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early.
  1388          */
  1389         <E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) {
  1390             switch (sym.kind) {
  1391                 case Kinds.MTH:
  1392                     return analyzer.process((MethodSymbol) sym);
  1393                 case Kinds.AMBIGUOUS:
  1394                     Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
  1395                     E res = defaultValue;
  1396                     for (Symbol s : err.ambiguousSyms) {
  1397                         if (s.kind == Kinds.MTH) {
  1398                             res = analyzer.reduce(res, analyzer.process((MethodSymbol) s));
  1399                             if (analyzer.shouldStop(res))
  1400                                 return res;
  1403                     return res;
  1404                 default:
  1405                     return defaultValue;
  1410     /** Analyzer for methods - used by analyzeCandidateMethods. */
  1411     interface MethodAnalyzer<E> {
  1412         E process(MethodSymbol ms);
  1413         E reduce(E e1, E e2);
  1414         boolean shouldStop(E result);
  1417     //where
  1418     private EnumSet<JCTree.Tag> deferredCheckerTags =
  1419             EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
  1420                     CONDEXPR, NEWCLASS, APPLY, LITERAL);

mercurial