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