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  */
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 =
66         new Context.Key<DeferredAttr>();
67 
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;
81 
instance(Context context)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     }
88 
DeferredAttr(Context context)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                 }
115 
116                 @Override
117                 public String toString() {
118                     return "Empty deferred context!";
119                 }
120             };
121     }
122 
123     /** shared tree for stuck expressions */
124     final JCTree stuckTree;
125 
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 {
133 
134         public JCExpression tree;
135         Env<AttrContext> env;
136         AttrMode mode;
137         SpeculativeCache speculativeCache;
138 
DeferredType(JCExpression tree, Env<AttrContext> env)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         }
145 
146         @Override
getTag()147         public TypeTag getTag() {
148             return DEFERRED;
149         }
150 
151         @Override
toString()152         public String toString() {
153             return "DeferredType";
154         }
155 
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 {
163 
164             private Map<Symbol, List<Entry>> cache =
165                     new WeakHashMap<Symbol, List<Entry>>();
166 
167             class Entry {
168                 JCTree speculativeTree;
169                 ResultInfo resultInfo;
170 
Entry(JCTree speculativeTree, ResultInfo resultInfo)171                 public Entry(JCTree speculativeTree, ResultInfo resultInfo) {
172                     this.speculativeTree = speculativeTree;
173                     this.resultInfo = resultInfo;
174                 }
175 
matches(MethodResolutionPhase phase)176                 boolean matches(MethodResolutionPhase phase) {
177                     return resultInfo.checkContext.deferredAttrContext().phase == phase;
178                 }
179             }
180 
181             /**
182              * Retrieve a speculative cache entry corresponding to given symbol
183              * and resolution phase
184              */
get(Symbol msym, MethodResolutionPhase phase)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             }
193 
194             /**
195              * Stores a speculative cache entry corresponding to given symbol
196              * and resolution phase
197              */
put(JCTree speculativeTree, ResultInfo resultInfo)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         }
207 
208         /**
209          * Get the type that has been computed during a speculative attribution round
210          */
speculativeType(Symbol msym, MethodResolutionPhase phase)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         }
215 
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          */
check(ResultInfo resultInfo)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         }
235 
check(ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy, DeferredTypeCompleter deferredTypeCompleter)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          */
complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext)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          */
isStuck()308         boolean isStuck();
309         /**
310          * Get the set of inference variables a given expression depends upon.
311          */
stuckVars()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          */
depVars()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      */
attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo)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;
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
visitClassDef(JCClassDecl tree)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         }
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<DeferredAttrNode>();
446 
DeferredAttrContext(AttrMode mode, Symbol msym, MethodResolutionPhase phase, InferenceContext inferenceContext, DeferredAttrContext parent, Warner warn)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          */
addDeferredAttrNode(final DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy)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          */
complete()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         }
521 
insideOverloadPhase()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     }
533 
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 {
539 
540         /** underlying deferred type */
541         DeferredType dt;
542 
543         /** underlying target type information */
544         ResultInfo resultInfo;
545 
546         /** stuck policy associated with this node */
547         DeferredStuckPolicy deferredStuckPolicy;
548 
DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy)549         DeferredAttrNode(DeferredType dt, ResultInfo resultInfo, DeferredStuckPolicy deferredStuckPolicy) {
550             this.dt = dt;
551             this.resultInfo = resultInfo;
552             this.deferredStuckPolicy = deferredStuckPolicy;
553         }
554 
555         /**
556          * Process a deferred attribution node.
557          * Invariant: a stuck node cannot be processed.
558          */
559         @SuppressWarnings("fallthrough")
process(final DeferredAttrContext deferredAttrContext)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         }
603 
604         /**
605          * Structural checker for stuck expressions
606          */
607         class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter {
608 
609             ResultInfo resultInfo;
610             InferenceContext inferenceContext;
611             Env<AttrContext> env;
612 
complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext)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             }
621 
622             @Override
visitLambda(JCLambda tree)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                     }
634 
635                     if (descriptorType.getParameterTypes().length() != tree.params.length()) {
636                         checkContext.report(tree,
637                                 diags.fragment("incompatible.arg.types.in.lambda"));
638                     }
639 
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();
653 
654                         tree.body.accept(lambdaBodyChecker);
655                         boolean isVoidCompatible = lambdaBodyChecker.isVoidCompatible;
656 
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                             }
669 
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             }
679 
canLambdaBodyCompleteNormally(JCLambda tree)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                     }
694 
695                     attr.attribStats(newTree.params, localEnv);
696 
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;
703 
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);
717 
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             }
733 
734             @Override
visitNewClass(JCNewClass tree)735             public void visitNewClass(JCNewClass tree) {
736                 //do nothing
737             }
738 
739             @Override
visitApply(JCMethodInvocation tree)740             public void visitApply(JCMethodInvocation tree) {
741                 //do nothing
742             }
743 
744             @Override
visitReference(JCMemberReference tree)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         }
778 
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;
787 
788             @Override
visitClassDef(JCClassDecl tree)789             public void visitClassDef(JCClassDecl tree) {
790                 // do nothing
791             }
792 
793             @Override
visitLambda(JCLambda tree)794             public void visitLambda(JCLambda tree) {
795                 // do nothing
796             }
797 
798             @Override
visitNewClass(JCNewClass tree)799             public void visitNewClass(JCNewClass tree) {
800                 // do nothing
801             }
802 
803             @Override
visitReturn(JCReturn tree)804             public void visitReturn(JCReturn tree) {
805                 if (tree.expr != null) {
806                     isVoidCompatible = false;
807                 } else {
808                     isPotentiallyValueCompatible = false;
809                 }
810             }
811         }
812     }
813 
814     /** an empty deferred attribution context - all methods throw exceptions */
815     final DeferredAttrContext emptyDeferredAttrContext;
816 
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 {
824 
825         DeferredAttrContext deferredAttrContext;
826 
DeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase)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         }
832 
833         @Override
apply(Type t)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         }
842 
typeOf(DeferredType dt)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     }
854 
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 {
863 
RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase)864         public RecoveryDeferredTypeMap(AttrMode mode, Symbol msym, MethodResolutionPhase phase) {
865             super(mode, msym, phase != null ? phase : MethodResolutionPhase.BOX);
866         }
867 
868         @Override
typeOf(DeferredType dt)869         protected Type typeOf(DeferredType dt) {
870             Type owntype = super.typeOf(dt);
871             return owntype == Type.noType ?
872                         recover(dt) : owntype;
873         }
874 
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          */
recover(DeferredType dt)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     }
892 
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 {
898 
899         final Filter<JCTree> treeFilter;
900 
FilterScanner(final Set<JCTree.Tag> validTags)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         }
908 
909         @Override
scan(JCTree tree)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         }
919 
920         /**
921          * handler that is executed when a node has been discarded
922          */
skip(JCTree tree)923         void skip(JCTree tree) {}
924     }
925 
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 {
931 
PolyScanner()932         PolyScanner() {
933             super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE));
934         }
935     }
936 
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 {
942 
LambdaReturnScanner()943         LambdaReturnScanner() {
944             super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
945                     FORLOOP, IF, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
946         }
947     }
948 
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 {
956 
957         Type pt;
958         Infer.InferenceContext inferenceContext;
959         Set<Type> stuckVars = new LinkedHashSet<Type>();
960         Set<Type> depVars = new LinkedHashSet<Type>();
961 
962         @Override
isStuck()963         public boolean isStuck() {
964             return !stuckVars.isEmpty();
965         }
966 
967         @Override
stuckVars()968         public Set<Type> stuckVars() {
969             return stuckVars;
970         }
971 
972         @Override
depVars()973         public Set<Type> depVars() {
974             return depVars;
975         }
976 
CheckStuckPolicy(ResultInfo resultInfo, DeferredType dt)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         }
986 
987         @Override
typesInferred(InferenceContext inferenceContext)988         public void typesInferred(InferenceContext inferenceContext) {
989             stuckVars.clear();
990         }
991 
992         @Override
visitLambda(JCLambda tree)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()));
1006             }
1007             scanLambdaBody(tree, descType.getReturnType());
1008         }
1009 
1010         @Override
visitReference(JCMemberReference tree)1011         public void visitReference(JCMemberReference tree) {
1012             scan(tree.expr);
1013             if (inferenceContext.inferenceVars().contains(pt)) {
1014                 stuckVars.add(pt);
1015                 return;
1016             }
1017             if (!types.isFunctionalInterface(pt)) {
1018                 return;
1019             }
1020 
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()));
1027             }
1028         }
1029 
scanLambdaBody(JCLambda lambda, final Type pt)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;
1038                 }
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;
1050                             }
1051                         }
1052                     }
1053                 };
1054                 lambdaScanner.scan(lambda.body);
1055             }
1056         }
1057     }
1058 
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 {
1066 
1067         boolean stuck;
1068 
1069         @Override
isStuck()1070         public boolean isStuck() {
1071             return super.isStuck() || stuck;
1072         }
1073 
OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt)1074         public OverloadStuckPolicy(ResultInfo resultInfo, DeferredType dt) {
1075             super(resultInfo, dt);
1076         }
1077 
1078         @Override
visitLambda(JCLambda tree)1079         public void visitLambda(JCLambda tree) {
1080             super.visitLambda(tree);
1081             if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT) {
1082                 stuck = true;
1083             }
1084         }
1085 
1086         @Override
visitReference(JCMemberReference tree)1087         public void visitReference(JCMemberReference tree) {
1088             super.visitReference(tree);
1089             if (tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
1090                 stuck = true;
1091             }
1092         }
1093     }
1094 
1095     /**
1096      * Does the argument expression {@code expr} need speculative type-checking?
1097      */
isDeferred(Env<AttrContext> env, JCExpression expr)1098     boolean isDeferred(Env<AttrContext> env, JCExpression expr) {
1099         DeferredChecker dc = new DeferredChecker(env);
1100         dc.scan(expr);
1101         return dc.result.isPoly();
1102     }
1103 
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 {
1109 
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;
1116 
1117         /**
1118          * Does this kind denote a poly argument expression
1119          */
isPoly()1120         public final boolean isPoly() {
1121             return this == POLY;
1122         }
1123 
1124         /**
1125          * Does this kind denote a primitive standalone expression
1126          */
isPrimitive()1127         public final boolean isPrimitive() {
1128             return this == PRIMITIVE;
1129         }
1130 
1131         /**
1132          * Compute the kind of a standalone expression of a given type
1133          */
standaloneKind(Type type, Types types)1134         static ArgumentExpressionKind standaloneKind(Type type, Types types) {
1135             return types.unboxedTypeOrType(type).isPrimitive() ?
1136                     ArgumentExpressionKind.PRIMITIVE :
1137                     ArgumentExpressionKind.NO_POLY;
1138         }
1139 
1140         /**
1141          * Compute the kind of a method argument expression given its symbol
1142          */
methodKind(Symbol sym, Types types)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);
1150             }
1151         }
1152     }
1153 
1154     /**
1155      * Tree scanner used for checking as to whether an argument expression
1156      * requires speculative attribution
1157      */
1158     final class DeferredChecker extends FilterScanner {
1159 
1160         Env<AttrContext> env;
1161         ArgumentExpressionKind result;
1162 
DeferredChecker(Env<AttrContext> env)1163         public DeferredChecker(Env<AttrContext> env) {
1164             super(deferredCheckerTags);
1165             this.env = env;
1166         }
1167 
1168         @Override
visitLambda(JCLambda tree)1169         public void visitLambda(JCLambda tree) {
1170             //a lambda is always a poly expression
1171             result = ArgumentExpressionKind.POLY;
1172         }
1173 
1174         @Override
visitReference(JCMemberReference tree)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;
1194             }
1195             //a method reference is always a poly expression
1196             result = ArgumentExpressionKind.POLY;
1197         }
1198 
1199         @Override
visitTypeCast(JCTypeCast tree)1200         public void visitTypeCast(JCTypeCast tree) {
1201             //a cast is always a standalone expression
1202             result = ArgumentExpressionKind.NO_POLY;
1203         }
1204 
1205         @Override
visitConditional(JCConditional tree)1206         public void visitConditional(JCConditional tree) {
1207             scan(tree.truepart);
1208             if (!result.isPrimitive()) {
1209                 result = ArgumentExpressionKind.POLY;
1210                 return;
1211             }
1212             scan(tree.falsepart);
1213             result = reduce(ArgumentExpressionKind.PRIMITIVE);
1214         }
1215 
1216         @Override
visitNewClass(JCNewClass tree)1217         public void visitNewClass(JCNewClass tree) {
1218             result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
1219                     ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
1220         }
1221 
1222         @Override
visitApply(JCMethodInvocation tree)1223         public void visitApply(JCMethodInvocation tree) {
1224             Name name = TreeInfo.name(tree.meth);
1225 
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;
1232             }
1233 
1234             //slow path
1235             Symbol sym = quicklyResolveMethod(env, tree);
1236 
1237             if (sym == null) {
1238                 result = ArgumentExpressionKind.POLY;
1239                 return;
1240             }
1241 
1242             result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
1243                     argumentKindAnalyzer);
1244         }
1245         //where
isSimpleReceiver(JCTree rec)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;
1264                 }
1265             }
reduce(ArgumentExpressionKind kind)1266             private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
1267                 return argumentKindAnalyzer.reduce(result, kind);
1268             }
1269             MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
1270                     new MethodAnalyzer<ArgumentExpressionKind>() {
1271                 @Override
1272                 public ArgumentExpressionKind process(MethodSymbol ms) {
1273                     return ArgumentExpressionKind.methodKind(ms, types);
1274                 }
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;
1285                     }
1286                 }
1287                 @Override
1288                 public boolean shouldStop(ArgumentExpressionKind result) {
1289                     return result.isPoly();
1290                 }
1291             };
1292 
1293         @Override
visitLiteral(JCLiteral tree)1294         public void visitLiteral(JCLiteral tree) {
1295             Type litType = attr.litType(tree.typetag);
1296             result = ArgumentExpressionKind.standaloneKind(litType, types);
1297         }
1298 
1299         @Override
skip(JCTree tree)1300         void skip(JCTree tree) {
1301             result = ArgumentExpressionKind.NO_POLY;
1302         }
1303 
quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree)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;
1308 
1309             if (rec != null && !isSimpleReceiver(rec)) {
1310                 return null;
1311             }
1312 
1313             Type site;
1314 
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;
1334                 }
1335             } else {
1336                 site = env.enclClass.sym.type;
1337             }
1338 
1339             while (site.hasTag(TYPEVAR)) {
1340                 site = site.getUpperBound();
1341             }
1342 
1343             site = types.capture(site);
1344 
1345             List<Type> args = rs.dummyArgs(tree.args.length());
1346             Name name = TreeInfo.name(tree.meth);
1347 
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);
1354                 }
1355                 @Override
1356                 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
1357                     return sym;
1358                 }
1359             };
1360 
1361             return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
1362         }
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;
1371                 }
1372                 @Override
1373                 public Symbol reduce(Symbol s1, Symbol s2) {
1374                     return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
1375                 }
1376                 @Override
1377                 public boolean shouldStop(Symbol result) {
1378                     return result == null;
1379                 }
1380             };
1381 
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          */
analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer)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;
1401                         }
1402                     }
1403                     return res;
1404                 default:
1405                     return defaultValue;
1406             }
1407         }
1408     }
1409 
1410     /** Analyzer for methods - used by analyzeCandidateMethods. */
1411     interface MethodAnalyzer<E> {
process(MethodSymbol ms)1412         E process(MethodSymbol ms);
reduce(E e1, E e2)1413         E reduce(E e1, E e2);
shouldStop(E result)1414         boolean shouldStop(E result);
1415     }
1416 
1417     //where
1418     private EnumSet<JCTree.Tag> deferredCheckerTags =
1419             EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,
1420                     CONDEXPR, NEWCLASS, APPLY, LITERAL);
1421 }
1422