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